﻿/// <reference path="../jqGrid/jqGrid-4.6.0/i18n/grid.locale-en.js" />
/// <reference path="../jqGrid/jqGrid-4.6.0/jquery.jqGrid.src.js" />
/// <reference path="../jQuery/jquery-1.11.0.js" />
/// <reference path="../jQuery-UI/jquery-ui-1.10.4.custom.js" />
/// <reference path="i18n/vpGrid-1.2.5.locale-en.js" />
/// <reference path="../qTip2/qTip2-2.2.0/jquery.qtip.js" />

///Author : Henri d'Orgeval

(function (window, undefined) {
    window.vpGrid = window.vpGrid || {};
    var vpGrid = window.vpGrid;
    vpGrid.version = "1.3.1";
})(this);


//Public options in vpGrid library
(function (window, undefined) {
    window.vpGrid = window.vpGrid || {};
    var vpGrid = window.vpGrid;
    vpGrid.defaultOptions = vpGrid.defaultOptions || {};
    vpGrid.defaultOptions.enableAutomaticPropagationOfUpdateInsertDeleteOperations = true;
    vpGrid.defaultOptions.enableUserInfo = false;
    vpGrid.defaultOptions.enableGlobalInfo = false;
    vpGrid.defaultOptions.enableRemoteLogging = false;
    vpGrid.defaultOptions.enableFilterToolbar = true;
    vpGrid.defaultOptions.enableOperatorsInFilterToolbar = false;
    vpGrid.defaultOptions.enableMultiSelect = false;
    vpGrid.defaultOptions.enableRowCheckbox = true;
    
    vpGrid.defaultOptions.enableCustomCaption = false;
    vpGrid.defaultOptions.enableCustomStatusBar = false;
    vpGrid.defaultOptions.enableSummaryRows = false;
    vpGrid.defaultOptions.enableInlineSummaryRows = false;
    vpGrid.defaultOptions.placeSummaryRowsOnTop = false;
    vpGrid.defaultOptions.numberOfSummaryRows = 1;
    vpGrid.defaultOptions.numberOfVisibleRows = 11;
    vpGrid.defaultOptions.loadGridOnPageLoad = true; 
    vpGrid.defaultOptions.minColWidth = 60;
    vpGrid.defaultOptions.fitToBrowserWidth = true;
    vpGrid.defaultOptions.fixedColWidth = false;
    vpGrid.defaultOptions.autoInsertNewLineAtBottom = false; // not implemented yet

    vpGrid.defaultOptions.defaultCaption = "My caption";
    vpGrid.defaultOptions.userInfoUrl = "";
    vpGrid.defaultOptions.globalInfoUrl = "";
    vpGrid.defaultOptions.remoteLoggingUrl = "";

    vpGrid.defaultOptions.enableColumnReordering = false;
    vpGrid.defaultOptions.locale = 'en';
    vpGrid.defaultOptions.showUIStateErrorsOnCellRendering = true;
    vpGrid.defaultOptions.enableInlineValidationOnInsert = false;

    vpGrid.defaultOptions.datepickerOptions = {
        dateFormat: 'yy/mm/dd',
        showOtherMonths: true,
        selectOtherMonths: true
    };

    vpGrid.defaultOptions.crudOptions =  {
        read: "MockRequests/GetData1.html",
        readOne: "MockRequests/read1.html",
        insert: "MockRequests/insert1.html",
        update: "MockRequests/update1.html",
        'delete': "MockRequests/delete1.html"
    };

    vpGrid.defaultOptions.jqGridOptions = {
        jgrid: {
            formatter: {
                //integer: { thousandsSeparator: ",", defaultValue: '0' },
                integer: { thousandsSeparator: " ", defaultValue: '0' },

                //number: { decimalSeparator: ".", thousandsSeparator: ",", decimalPlaces: 2, defaultValue: '0.00' },
                number: { decimalSeparator: ",", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0,00' },

                //currency: { decimalSeparator: ".", thousandsSeparator: ",", decimalPlaces: 2, prefix: "", suffix: " $", defaultValue: '0' },
                currency: { decimalSeparator: ",", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix: " €", defaultValue: '0' },

                date: { srcformat: 'Y-m-d', newformat: 'Y/m/d' },
                checkbox: { disabled: false }
            }
        }
    };


    vpGrid.initOptions = function (options) {
        try {

            if (options === undefined || options === null) {
                vpGrid.options = $.extend({}, vpGrid.defaultOptions);
                return;
            }

            vpGrid.options = $.extend({}, vpGrid.defaultOptions, options);

            //do some special checks
            if (vpGrid.options.enableCustomCaption === true && 
                (vpGrid.options.defaultCaption === '' || vpGrid.options.defaultCaption === undefined || vpGrid.options.defaultCaption === null)
                ) {
                vpGrid.options.defaultCaption = "_";
            }

        } catch (e) {
            if (vpGrid.logException) {
                vpGrid.logException(e);
            }

        }
    };

})(this);
//End Public options in vpGrid library


//Public events raised by vpGrid
(function (window, undefined) {
    window.vpGrid = window.vpGrid || {};
    var vpGrid = window.vpGrid;
    
    vpGrid.Event = vpGrid.Event || {};
    vpGrid.Event.onSecurityTrimming = "onSecurityTrimming";
    vpGrid.Event.onTimelineCreated = "onTimelineCreated";
    vpGrid.Event.onBehaviorsRegistering = "onBehaviorsRegistering";
    vpGrid.Event.onBehaviorsRegistered = "onBehaviorsRegistered";
    vpGrid.Event.onTimelineExecuting = "onTimelineExecuting";


    vpGrid.Event.onDataReceived = "onDataReceived";
    //This event is raised when the response data has been received from remote server.
    //this event enables to change the received data before loading it in the grid.
    //for example the server might sent "compressed data" or "unreadable" data to optimize security and bandwidth
    //this event enables listener to transform a non readable received data into a meaningfull data.
    //Listeners might also add or remove any data to or from the received data.
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        data: [{col1:xxx, col2:yyy, ... colN:zzz}, ...]
    //      };
    // The data property of the eventArgs object is an array of objects. Each object in the array represent a row in the grid. 
    // The property names of these objects must be the name of an existing column in the grid.


    vpGrid.Event.onUpdatedDataReceived = "onUpdatedDataReceived";
    //This event is raised when the response data has been received from remote server due to a data update on server-side.
    //this event enables to do any post processing on updated data
    //for example the caller might upload files or do any ajax request on the real updated data
    //The listener must not change any data embeded in the eventArgs object
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //              sentData: {col1:xxx, col2:yyy, ... colN:zzz, extraData1:ttt, extraData2:uuu, ..., extraDataN:www},     -> Data sent to the server to make the server-side update
    //              receivedData: {col1:xxx, col2:yyy, ... colN:zzz}, -> Data sent back by the server after the server-side update operation
    //              keyName:      -> name of the key that identifies the entity on server side
    //              keyValue:       -> value of the key
    //      };
    // The sentData property of the eventArgs object represents the client-side updated row in the grid. 




    vpGrid.Event.onInsertedDataReceived = "onInsertedDataReceived";
    //This event is raised when the response data has been received from remote server due to a data insert on server-side.
    //this event enables listeners to do any post processing on inserted data
    //for example the caller might upload files or do any ajax request on the real inserted data
    //The listener must not change any data embeded in the eventArgs object
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //              sentData: {col1:xxx, col2:yyy, ... colN:zzz, extraData1:ttt, extraData2:uuu, ..., extraDataN:www},     -> Data sent to the server to make the server-side insert
    //              receivedData: {col1:xxx, col2:yyy, ... colN:zzz}, -> Data sent back by the server after the server-side insert operation
    //              keyName:      -> name of the key that identifies the entity on server side
    //              keyValue:       -> value of the key of the new inserted entity
    //      };
    // The sentData property of the eventArgs object represents the client-side inserted row in the grid. 
    // The listener should not modify the eventArgs.receivedData content.




    vpGrid.Event.onInsertingDataOnRemote = "onInsertingDataOnRemote";
    //This event is raised when a data row is about to be sent to the remote server for an INSERT operation  
    // This event enable listeners to cancel this CRUD operation upon specific business rules 
    //                                  (for example the row has content but is empty in terms of business data)
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        data: data, -> literal object that holds the data that will be sent to the server
    //        cancel : false|true (false by default)
    //        cancelReason : ""
    //      };
    // The event handler can inspect the data object, can modify it, can add properties
    // To prevent the data to be sent, the event handler must set the cancel property to true. 
    // Optionnaly the event handler should set a message to tell the user why this data should not be sent to server




    vpGrid.Event.onUpdatingDataOnRemote = "onUpdatingDataOnRemote";
    //This event is raised when a data row is about to be sent to the remote server for an UPDATE operation  
    // This event enable listeners to cancel this CRUD operation upon specific business rules 
    //                                  (for example the row has content but is empty in terms of business data)
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        data: data, -> literal object that holds the data that will be sent to the server
    //        cancel : false|true (false by default)
    //        cancelReason : ""
    //      };
    // The event handler can inspect the data object, can modify it, can add properties
    // To prevent the data to be sent, the event handler must set the cancel property to true. 
    // Optionnaly the event handler should set a message to tell the user why this data should not be sent to server



    vpGrid.Event.onDeletingDataOnRemote = "onDeletingDataOnRemote";
    //This event is raised when a data row is about to be sent to the remote server for a DELETE operation  
    // This event enable listeners to cancel this CRUD operation upon specific business rules 
    //                                  (for example the row has content but is empty in terms of business data)
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        data: data, -> literal object that holds the data that will be sent to the server
    //        cancel : false|true (false by default)
    //        cancelReason : ""
    //      };
    // The event handler can inspect the data object, can modify it, can add properties
    // To prevent the data to be sent, the event handler must set the cancel property to true. 
    // Optionnaly the event handler should set a message to tell the user why this data should not be sent to server


    vpGrid.Event.onDataInsertedUpdatedDeletedOnRemote = "onDataInsertedUpdatedDeletedOnRemote";
    //This event is raised when when all CRUD operations have been performed by the grid  
    // This event enable listeners to do post processing only when all the INSERT/UPDATE/DELETE have been done. 
    //                                  (for example reloading the grid)
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        -> eventArgs does not need to have any content for this event
    //      };
    



    vpGrid.Event.onCellRendering = "onCellRendering";
    //This event is raised when a cell is rendering and jqGrid is about to render the <td> cell container.
    //this event enables to setup the html attributes of the <td> cell container. 
    //You cannot set the <td> html content with this event.
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        cellName: cellname,
    //        cellValue: value,
    //        rowData: data,
    //        td : {}
    //      };
    // The event handler can set the eventArgs.td literal object with properties corresponding to html attributes.
    // for example : eventArgs.td.title = 'xxx', eventArgs.td.class = 'myclass', eventArgs.td.style="xxx'



    vpGrid.Event.onSummaryCellRendering = "onSummaryCellRendering";
    //This event is raised when a summary cell is rendering.
    //this event enables to setup the value of the summary cell and also the html attributes of the <td> cell container.
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        cellName: cellname,
    //        cellValue: value,
    //        useCellFormatter : false,
    //        uiIdentifier : xxxx  -> value of the data tag data-vpgrid-ui-id
    //        td : {},
    //        remove :{}
    //        isAsync: true -> this event is async. you cannot revert it back to be synchronous
    //        asyncInit : function(){} -> call this method at the beginning of your event handler
    //        asyncEnd : function(){}  -> call this method when your event handler has finished its task (be it asynchronous or synchronous)
    //      };
    // 
    // The event handler can set the eventArgs.td literal object with properties corresponding to html attributes.
    // The uiIdentifier property enables listener to know on which summary row he is called:
    //          if there is only one summary row (this is the default): uiIdentifier=""
    //          if there are more than one summary row: uiIdentifier = "SumarryRowN" where N = 1,2,3, ...
    // If existing attributes or classes must be removed, the event handler should fill the remove property.
    // For example, to remove the ui-state-error class on the td : remove.class='ui-state-error'.
    // for example : eventArgs.td.title = 'xxx', eventArgs.td.class = 'myclass', eventArgs.td.style="xxx'
    // The Event handler should also setup the cellValue property. This value will be rendered in the cell summary.
    // If cellValue must be rendered in the same format as other cells in the column, the event handler should explicitely set the useCellFormatter property to true.



    vpGrid.Event.onSelectCellRendering = "onSelectCellRendering";
    //This event is raised when a cell is in edit mode and needs to be rendered as a select statement <select>...</select>
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        cellName: cellname,
    //        cellValueBeforeEditing: value,
    //        rowData: data,
    //        selectOptions : []
    //      };
    // The event handler should fill the eventArgs.selectOptions with literal objects of type : { key : xxx, value : yyy} (a collection of key/value pairs)
    // if there is no listener or if listener(s) does nothing, the selectOptions array will be be automatically filled with all distinct values of the column.



    vpGrid.Event.onAutocompleteCellRendering = "onAutocompleteCellRendering";
    //This event is raised when a cell is in edit mode and needs to be rendered as an input statement <input>...</input> with autocomplete bound to it.
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        cellName: cellname,
    //        cellValue: value,
    //        options : {},  -> options parameter of autocomplete jquery-ui
    //        data: [],
    //        rowData: data
    //      };
    // The event handler should fill the eventArgs.data array with strings. This array will be bound to autocomplete.
    // if there is no listener or if listener(s) does nothing, the data array will be be automatically filled with all distinct values of the column.



    vpGrid.Event.onImageCellRendering = "onImageCellRendering";
    //This event is raised when a cell is in display mode and needs to be rendered as an image statement <img>...</img>



    vpGrid.Event.onLinkCellRendering = "onLinkCellRendering";
    //This event is raised when a cell is in display mode and needs to be rendered as a link statement <a>...</a>
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      var eventArgs = {
    //          cellName,
    //          cellValue,
    //          rowData: data,
    //          a: {
    //              href: cellValue,
    //              title: cellValue,
    //              target: target,
    //              },
    //          html: linkContent
    //      };
    // The event handler can set the eventArgs.a literal object with properties corresponding to html attributes.
    // The event handler can set the eventArgs.html to the string that will be rendered as a link.
    // The event handler must not change eventArgs.cellName, eventArgs.cellValue and cellValue.rowData.



    vpGrid.Event.onCellValidating = "onCellValidating";
    //This event is raised when a cell is in edit mode and needs to be validated through custom validation
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        cellName: cellname,
    //        cellValue: value, -> cellValue is always a string
    //        cellNativeValue : cellValue converted to the column schema data type (only works for numbers at the moement)
    //        rowData: -> literal object that contains all cells in the selected row (Inline Cell Editing): {col1:xxx, col2:yyy, ... colN:zzz}
    //        dialogData, ->literal object that contains all input fields in the jQuery-UI Dialog window (Form Editing) : {col1:xxx, col2:yyy, ... colN:zzz}
    //        dialogId, -> vpGrid Id of the jQuery-UI Dialog representing the input Form 
    //        isValid : true,
    //        errorMessage : 'xxx'
    //      };
    // The event handler should set the eventArgs.isValid property to false and the eventArgs.errorMessage property if custom validation fails.



    vpGrid.Event.onCellUpdating = "onCellUpdating";
    // This Event is raised when a cell is in edit mode and the underlying data is about to be updated.



    vpGrid.Event.onCellUpdated = "onCellUpdated";
    //This event is raised when a cell has been updated on client-side (after its content has been edited)
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        cellName, -> name of the cell that has been edited 
    //        cellValue, -> value of the edited cell
    //        rowid, -> id of the HTML table row that holds the updated cell
    //        rowData -> literal object that contains all cells in the row : {col1:xxx, col2:yyy, ... colN:zzz}
    //      };
    // The event handler uses eventArgs properties to make any additional processing on the grid. 
    // For example: 
    //      - changing other cells of the same row by applying specific business rules.
    //          -> to change another cell, the event listener may set the rowData.colName property of the corresponding cell
    //      - updating the summary row by calling vpGrid.renderSummaryRows()




    vpGrid.Event.onRowEditing = "onRowEditing";
    //This event is raised when the user click on a row to edit a cell or to delete the row  
    // This event enable listeners to cancel any modification on the row when the user click on a cell for editing
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        rowid: id, -> HTML TR id of the clicked row
    //        rowData: data, -> literal object that holds the data of the clicked row
    //        cancel : false|true (false by default)
    //        cancelReason : ""
    //      };
    // The event handler can inspect the rowData data object but cannot modify it
    // To make the row readonly, the event handler must set the cancel property to true. 
    // Optionnaly the event handler should set a message to tell the user the row is read only.
    



    vpGrid.Event.onCellEditing = "onCellEditing";
    //This event is raised when the user click on a cell to edit its content 
    // This event enable listeners to prevent user to edit the clicked cell
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        rowid: id, -> HTML TR id of the clicked row
    //        rowData: data, -> literal object that holds the data of the clicked row
    //        cellName: xxx -> name of the cell clicked by the user
    //        cancel : false|true (false by default)
    //        cancelReason : ""
    //      };
    // The event handler can inspect the rowData data object but cannot modify it
    // To make the cell readonly, the event handler must set the cancel property to true. 
    // Optionnaly the event handler should set a message to tell the user why the cell is read only.








    vpGrid.Event.onRowInserted = "onRowInserted";
    //This event is raised when a row has been inserted in the grid. 
    // This event is raised when data is loaded from server and when data has been filtered/sorted in the grid.
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        rowid: id, 
    //        rowData: data
    //      };
    // The event handler uses eventArgs properties to make any additional processing on the grid. 
    // For example: 
    //      - changing other cells of the same row by applying specific business rules.
    //          -> to change another cell, the event listener may set the rowData.colName property of the corresponding cell
    // To add or update inline summary rows, you MUST use the onInlineSummaryRowRendering event




    vpGrid.Event.onInlineSummaryRowRendering = "onInlineSummaryRowRendering";
    //This event is raised when a row has been inserted in the grid. 
    // This event is raised when data is loaded from server, when data has been filtered/sorted in the grid.
    // This event enable listeners to insert/update inline summary rows for the target row
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        rowid: id, 
    //        rowData: data
    //      };
    // The event handler uses eventArgs properties as input data to create or update an inline summary row.
    // inline summary rows are created/updated using the public methods : 
    //                                              vpGrid.insertInlineSummaryRowAfter,
    //                                              vpGrid.updateInlineSummaryRowAfter,
    //                                              vpGrid.insertInlineSummaryRowBefore,
    //                                              vpGrid.updateInlineSummaryRowBefore,







    vpGrid.Event.onModalDialogClosing = "onModalDialogClosing";


    vpGrid.Event.onModalDialogClosed = "onModalDialogClosed";
    //Event raised when a modal dialog is closed. 
    //Event listener must have the signature function(source, eventArgs){}


    vpGrid.Event.onModalDialogOpening = "onModalDialogOpening";
    //This event is raised when a modal dialog is about to be opened
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //          dialogId : '' -> vpgrid id of the modal dialog (enables the listener to know on which form he is called)
    //          dialogData : literal object that contains all column fields found in the form
    //          rowData : literal object that represent the select row in the Grid
    //          cancel : false|true (false by default)
    //          cancelReason : "",
    //          iframeUrl: url of the iframe
    //      };
    // The event handler can inspect the dialogData data object but cannot modify it
    // The event handler can do any additional processing (that do not need immediate rendering) on the jquery ui-dialog (for example doing some custom initialization)
    // The event handler can prevent the dialog to open by setting the cancel property to true and by setting the cancelReason to a message explaining why the dialog cannot open.
    // When this event is raised to open an external web page in an iframe, the event handler can change this url by setting the property iframeUrl.


    vpGrid.Event.onModalDialogOpened = "onModalDialogOpened";
    //This event is raised when a modal dialog is opened
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //          dialogId : '' -> vpgrid id of the modal dialog (enables the listener to know on which form he is called)
    //          dialogData : literal object that contains all column fields found in the form
    //      };
    // The event handler can inspect the dialogData data object but cannot modify it
    // The event handler can do any additional processing (that do not need immediate rendering) on the jquery ui-dialog (for example doinf some custom initialization)


    vpGrid.Event.onFormValidating = "onFormValidating";
    //This event is raised when a form needs to be validated through a custom global validation
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        modalDialogId : '' -> id of the parent modal dialog (enables the listener to know on which form he is called)
    //        validationResult: validationResult, -> literal object that contains all column fields found in the form:
    //              validationResult["colname"]= {
    //                                      isValid: true -> set this property to false if business validation fails on this field
    //                                      message : 'put here the error message for the specified field'
    //                                      value : "xxxx"   -> value entered by the user in the field (this value is always a string)
    //                                  }
    //        isValid: true
    //      };
    // The event handler can inspect/modify the validationResult object
    // The event handler should set the eventArgs.isValid property to false if custom validation fails.





    vpGrid.Event.onFileuploading = "onFileuploading";
    //This event is raised when a file is about to be uploaded
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //          data : data, -> data object built by the jquery File Upload plugin
    //          formData: formData, -> literal Object that will be added in the POST Request
    //          cancel : false
    //      };
    // The event handler can prevent the file to be uploaded by setting the cancel property to true.
    // The event handler may send any additional data (key/value) to the server by extending the formData object.
    // The event handler must not modify the data eventArgs.data object : modfying it is at your own risk.





    vpGrid.Event.onUIElementDisabling = "onUIElementDisabling";
    //This event is raised when a DOM element is about to be disabled in the UI
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        uiId: xxx , -> value of the data-vpgrid-ui-id attribute that has been setup on the element
    //        cancel: true|false -> default value is false

    //      };
    // The event handler should set the eventArgs.cancel property to true if the DOM element should be enabled due to specific business rules.

    vpGrid.Event.onUIElementEnabling = "onUIElementEnabling";
    //This event is raised when a DOM element is about to be enabled in the UI
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        uiId: xxx , -> value of the data-vpgrid-ui-id attribute that has been setup on the element
    //        cancel: true|false -> default value is false
    //        selectedRowData : { } -> literal object that holds the data for the selected row (the row that is checked (first column) in jqGrid)
    //                                 If no row is checked, the selectRowData is null or is missing
    //      };
    // The event handler should set the eventArgs.cancel property to true if the DOM element should be disabled due to specific business rules.



    vpGrid.Event.onGridLoaded = "onGridLoaded";
    //This event is raised when the Grid has received data and loaded it in jqGrid.
    //this event enables listener to do post-processing on the UI when the grid has loaded its data.
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        
    //      };
    

    vpGrid.Event.onUserInfoReady = "onUserInfoReady";
    //This event is raised when the user info object has been constructed from the data requested to the server.
    //this event enables to change or augment the userInfo object.
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        userInfo: {
    //                      name : "name of the user",
    //                      login : "login of the user",
    //                      roles : ["role1", "role2", ...] -> string array that lists all roles the user is in.
    //            }
    //      };
    //
    // After this event is raised, the userInfo object is available at vpGrid.currentUser


    vpGrid.Event.onGlobalInfoReady = "onGlobalInfoReady";
    //This event is raised when the global info object has been constructed from the data requested to the server.
    //this event enables to change or augment the globalInfo object.
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        globalInfo: {
    //                      prop1 : xxxx,
    //                      prop2 : yyyy
    //            }
    //      };
    //
    // After this event is raised, the globalInfo object is available at vpGrid.globalInfo

    vpGrid.Event.onWindowClosing = "onWindowClosing";
    //This event is raised when the user closes the browser window or when the user refreshes the web page (F5)  
    // This event enable listeners to cancel the closing operation upon specific business rules 
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        data: data, -> literal object that holds the data that will be sent to the server
    //        cancel : false|true (false by default)
    //        cancelReason : ""
    //      };
    // The event handler can inspect the data object, but MUST NOT modify it
    // To prevent the window from closing, the event handler must set the cancel property to true. 
    // Optionnaly the event handler should set a message to tell the user why the window cannot be closed


    vpGrid.Event.onDataRowValidating = "onDataRowValidating";
    //This event is raised when a dataRow needs to be validated through a custom global validation
    //Event handler must have the following signature : function(source, eventArgs)
    //the eventArgs parameter has the following signature : 
    //      eventArgs = {
    //        rowData: data, -> literal object that holds the data of a row 
    //        isValid: true|false
    //        errors : [] -> array of objects containing all errors in the dataRow
    //                      each object in the array must have the following signature:
    //                      {
    //                          propertyName : string -> name of a column/field
    //                          message : string -> put here the error message for the specified column/field
    //                      }
    //      };
    // The event handler should set the eventArgs.isValid property to false if custom validation fails.
    // If validation fails, the Event handler should push all error messages as object literals in the errors array


})(this);
//End Public Events enumeration



//Public Data Tag and role attributes
(function (window, undefined) {
    window.vpGrid = window.vpGrid || {};
    var vpGrid = window.vpGrid;

    // data tags attributes are used to inject custom behaviors within the Grid
    vpGrid.HtmlDataTag = vpGrid.HtmlDataTag || {};
    vpGrid.HtmlDataTag.TimelineSequence = "data-vpgrid-timeline-sequence";
    vpGrid.HtmlDataTag.DataSource = "data-vpgrid-datasource";
    vpGrid.HtmlDataTag.DataSourceType = "data-vpgrid-datasource-type";
    vpGrid.HtmlDataTag.DataSourceIsBinding = "data-vpgrid-datasource-is-binding";
    vpGrid.HtmlDataTag.Url = "data-vpgrid-url";
    vpGrid.HtmlDataTag.UIElement = "data-vpgrid-ui-element";
    vpGrid.HtmlDataTag.Handlers = "data-vpgrid-handlers";
    vpGrid.HtmlDataTag.HandlersRegistered = "data-vpgrid-handlers-registered";
    
    vpGrid.HtmlDataTag.ValidationHandlersRegistered = "data-vpgrid-validation-handlers-registered";
    vpGrid.HtmlDataTag.UIDisabled = "data-vpgrid-ui-disabled";
    vpGrid.HtmlDataTag.UIDisabledOn = "data-vpgrid-ui-disabled-on";
    vpGrid.HtmlDataTag.UIIdentifier = "data-vpgrid-ui-id";
    vpGrid.HtmlDataTag.SummaryIdentifier = "data-vpgrid-summary-id";
    vpGrid.HtmlDataTag.ImportColumnValue = "data-vpgrid-import-column-value";
    vpGrid.HtmlDataTag.OriginalValue = "data-vpgrid-original-value";
    vpGrid.HtmlDataTag.RowMustBeRemoved = "data-vpgrid-row-must-be-removed";

    // This Data tag is used to know if the current element has been attached to its container. For exemple the element is defined outside its container and then placed at a specific time at a specific place in the DOM.
    vpGrid.HtmlDataTag.UIInPlace = "data-vpgrid-ui-inplace";

    vpGrid.HtmlDataTag.UIContentPlaceholder = "data-vpgrid-ui-content-placeholder";

    //default values for data tag
    vpGrid.HtmlDataTag.DefaultValue = vpGrid.HtmlDataTag.DefaultValue || {};
    vpGrid.HtmlDataTag.DefaultValue.DataSourceType = "web";

    //data tags for security trimming managment
    vpGrid.HtmlDataTag.securityTrimmed = "data-vpgrid-security-trimmed";
    vpGrid.HtmlDataTag.securityTrimmedRoles = "data-vpgrid-security-trimmed-roles";
    vpGrid.HtmlDataTag.securityTrimmedUrl = "data-vpgrid-security-trimmed-url";
    vpGrid.HtmlDataTag.securityTrimmedSequence = "data-vpgrid-security-trimmed-sequence";
    vpGrid.HtmlDataTag.securityTrimmedRolesType = "data-vpgrid-security-trimmed-roles-type";

    //data tags for the creation and the configuration of the grid columns
    vpGrid.HtmlDataTag.ColumnName = "data-vpgrid-column-name";
    vpGrid.HtmlDataTag.ColumnWidth = "data-vpgrid-column-width";
    vpGrid.HtmlDataTag.ColumnFixedWidth = "data-vpgrid-column-fixed-width";
    vpGrid.HtmlDataTag.ColumnHidden = "data-vpgrid-column-hidden";
    vpGrid.HtmlDataTag.ColumnEditable = "data-vpgrid-column-editable";
    vpGrid.HtmlDataTag.ColumnEditType = "data-vpgrid-column-edittype";
    vpGrid.HtmlDataTag.ColumnAlign = "data-vpgrid-column-align";
    vpGrid.HtmlDataTag.ColumnType = "data-vpgrid-column-type";
    vpGrid.HtmlDataTag.ColumnCSS = "data-vpgrid-column-css";
    vpGrid.HtmlDataTag.ColumnFrozen = "data-vpgrid-column-frozen";
    vpGrid.HtmlDataTag.ColumnMinValue = "data-vpgrid-column-min-value";
    vpGrid.HtmlDataTag.ColumnMaxValue = "data-vpgrid-column-max-value";
    vpGrid.HtmlDataTag.ColumnUniqueValueConstraint = "data-vpgrid-column-unique-value-constraint";
    vpGrid.HtmlDataTag.ColumnRemoteValidationUrl = "data-vpgrid-column-remote-validation-url";
    vpGrid.HtmlDataTag.ColumnSortable = "data-vpgrid-column-sortable";
    vpGrid.HtmlDataTag.ColumnFilterable = "data-vpgrid-column-filterable";
    vpGrid.HtmlDataTag.ColumnPlaceholder = "data-vpgrid-column-placeholder";
    vpGrid.HtmlDataTag.ColumnActionType = "data-vpgrid-column-actiontype";
    vpGrid.HtmlDataTag.ColumnLocked = "data-vpgrid-column-locked"; //not implemented yet
    vpGrid.HtmlDataTag.ColumnInfo = "data-vpgrid-column-info";
    vpGrid.HtmlDataTag.ColumnSummaryAlwaysUpdate = "data-vpgrid-column-summary-always-update";
    vpGrid.HtmlDataTag.ColumnRequired = "data-vpgrid-column-required";
    vpGrid.HtmlDataTag.SelectOptions = "data-vpgrid-select-options";

    //data tags for automatic creation and configuration of jQuery-UI widgets
    vpGrid.HtmlDataTag.DialogId = "data-vpgrid-dialog-id";
    vpGrid.HtmlDataTag.UIWidget = "data-vpgrid-ui-widget";
    vpGrid.HtmlDataTag.UIWidgetOptions = "data-vpgrid-ui-widget-options";

    //data tags for remote filtering
    vpGrid.HtmlDataTag.RemoteDataFilterKey = "data-vpgrid-remote-data-filter-key";
    vpGrid.HtmlDataTag.RemoteDataFilterName = "data-vpgrid-remote-data-filter-name";
    vpGrid.HtmlDataTag.RemoteDataFilterColumnName = "data-vpgrid-remote-data-filter-column-name";
    vpGrid.HtmlDataTag.RemoteDataFilterOperator = "data-vpgrid-remote-data-filter-operator";

    //data tags for backup/restore/augmentation
    vpGrid.HtmlDataTag.CssToAdd = "data-vpgrid-css-to-add";
    vpGrid.HtmlDataTag.OriginalClassAttributeContent = "data-vpgrid-original-class-attribute-content";

    //public Role attributes used by vpGrid
    // Role attributes are used by vpGrid to locate specific parts of the grid or elements used by the grid.
    vpGrid.HtmlRoleAttribute = vpGrid.HtmlRoleAttribute || {};
    vpGrid.HtmlRoleAttribute.vpGridContainer = "vpgrid-container";
    vpGrid.HtmlRoleAttribute.vpGridBody = "vpgrid-body";
    vpGrid.HtmlRoleAttribute.vpGridSchema = "vpgrid-schema";
    vpGrid.HtmlRoleAttribute.vpGridSchemaColumns = "vpgrid-schema-columns";
    vpGrid.HtmlRoleAttribute.vpGridSchemaCaption = "vpgrid-schema-caption";
    vpGrid.HtmlRoleAttribute.vpGridSchemaColumnsGroup = "vpgrid-schema-columns-group";
    vpGrid.HtmlRoleAttribute.vpGridSchemaStatusBar = "vpgrid-schema-status-bar";
    vpGrid.HtmlRoleAttribute.Titlebar = "vpgrid-dialog-title-bar";
    vpGrid.HtmlRoleAttribute.vpGridModalDialog = "vpgrid-modal-dialog";
    vpGrid.HtmlRoleAttribute.RemoteDataFilter = "vpgrid-remote-data-filter";
    vpGrid.HtmlRoleAttribute.ActiveHeader = "vpgrid-active-header";
    vpGrid.HtmlRoleAttribute.vpGridRibbon = "vpgrid-ribbon";
    vpGrid.HtmlRoleAttribute.vpGridPartialUI = "vpgrid-partial-ui";

})(this);
//End Public Data Tag and role attributes enumeration


//Public User Info object definition
(function (window, undefined) {
    window.vpGrid = window.vpGrid || {};
    var vpGrid = window.vpGrid;
    vpGrid.currentUser = vpGrid.currentUser || {};
    var currentUser = vpGrid.currentUser;

    currentUser.name = "";
    currentUser.login = "";
    currentUser.roles = [];

    function isNullOrUndefined(input) {
        try {
            if (input === undefined) {
                return true;
            }

            if (input === null) {
                return true;
            }

            return false;

        } catch (e) {
            //TODO : log
            vpGrid.logException(e);
            return false;
        }
    }
    function isString(input) {
        try {
            if (isNullOrUndefined(input)) {
                return false;
            }

            if (typeof input === "string") {
                return true;
            }
            //hack from hdo
            if (typeof input.isString !== "function") {
                return false;
            }

            if (input.isString()) {
                return true;
            }

            return false;

        } catch (e) {
            vpGrid.logException(e);
            return false;
        }
    };

    function isNotString(input) {
        return isString(input) === false;
    };

    currentUser.isInRole = function (role) {
        /// <signature>
        /// <summary>Check if current user is in a specific role</summary>
        /// <param name="role" type="String">Name of the role</param>
        /// <returns type="Number">Returns true if the user is in input role</returns>
        /// </signature>
        try {

            if (isNotString(role)) {
                vpGrid.logError({
                    functionName: "isInRole",
                    message: "role parameter is not a valid string : '" + role + "' ",
                    info : "IsInRole will return false."
                });
                return false;
            }

            if (role.isInArray(vpGrid.currentUser.roles)) {
                return true;
            }

            return false;

        } catch (e) {
            vpGrid.logException(e);
            return false;
        }

    };

    currentUser.isNotInRole = function (role) {
        /// <signature>
        /// <summary>Check if current user is not in a specific role</summary>
        /// <param name="role" type="String">Name of the role</param>
        /// <returns type="Number">Returns true if the user is not in input role</returns>
        /// </signature>
        return currentUser.isInRole(role) === false;

    };

})(this);

//Public Global Info object definition
(function (window, undefined) {
    window.vpGrid = window.vpGrid || {};
    var vpGrid = window.vpGrid;
    vpGrid.globalInfo = vpGrid.globalInfo || {};
    var globalInfo = vpGrid.globalInfo;

    function isNullOrUndefined(input) {
        try {
            if (input === undefined) {
                return true;
            }

            if (input === null) {
                return true;
            }

            return false;

        } catch (e) {
            //TODO : log
            vpGrid.logException(e);
            return false;
        }
    }
    function isString(input) {
        try {
            if (isNullOrUndefined(input)) {
                return false;
            }

            if (typeof input === "string") {
                return true;
            }
            //hack from hdo
            if (typeof input.isString !== "function") {
                return false;
            }

            if (input.isString()) {
                return true;
            }

            return false;

        } catch (e) {
            vpGrid.logException(e);
            return false;
        }
    };

    function isNotString(input) {
        return isString(input) === false;
    };

    

})(this);


(function (window, $, undefined) {
    try {
        window.vpGrid = window.vpGrid || {};
        var vpGrid = window.vpGrid;

        var vpGridAjaxOptions = {
            error: logAjaxError,
            beforeSend: function (xhr, settings) {
                try {
                    //inject custom property in the xhr object the request Url
                    //for logging purpose in case response code != 200
                    xhr.requestURL = settings.url;
                } catch (e) {
                    vpGrid.logException(e);
                }
                
            }
        };

        // variable to create unique client side id for new inserted rows
        vpGrid.guid = vpGrid.guid || 1;

        //trace API
        function logExceptionToConsole(ex) {
            try {
                if (ex === undefined) {
                    return;
                }

                if (console === undefined) {
                    return;
                }

                if (console.error === undefined) {
                    return;
                }

                var smalldateTime = new Date().toSmallDateTime();
                var msg = "[" + smalldateTime + "] ";

                if (ex.stack) {
                    msg += ex.stack;
                    console.error(msg);
                    return;
                }

                if (ex.message) {
                    msg += ex.message;
                }

                console.error(msg);

            } catch (e) {
                var msg = e.message;
            }
        }

        function remoteLoggingIsEnabled() {
            try {

                if (vpGrid.options.enableRemoteLogging === true) {
                    return true;
                }

                return false;
            } catch (e) {
                logExceptionToConsole(e);
                return false;
            }
        }

        function remoteLoggingIsNotEnabled() {
            return remoteLoggingIsEnabled() === false;
        }

        function sendExceptionToRemote(ex) {
            try {
                //check if sending messages to remote server is enabled
                if (remoteLoggingIsNotEnabled()) {
                    return;
                }

                if (isNullOrUndefinedOrEmpty(vpGrid.options.remoteLoggingUrl)) {
                    vpGrid.logError({
                        functionName : "sendExceptionToRemote",
                        message: "The remoteLoggingUrl option is not defined. Errors cannot be sent to remote server.",
                        info: "Check that you have the remoteLoggingUrl option set in the options object passed to the vpGrid.init() method."
                    });
                    return;
                }

                var requestUrl = vpGrid.options.remoteLoggingUrl;
                requestUrl += '?ex=' + encodeURIComponent(JSON.stringify(ex));
                var img = new Image();
                img.src = requestUrl;

            } catch (e) {
                logExceptionToConsole(e);
            }
        }

        vpGrid.logException = function (ex) {
            /// <signature>
            /// <summary>Log exception on all configured output devices (Console, Remote Server, custom DOM element</summary>
            /// <param name="ex" type="Object">exception object</param>
            /// </signature>
            try {
                logExceptionToConsole(ex);

                sendExceptionToRemote(ex);

                //TODO : log inside specific DOM element

            } catch (e) {
                logExceptionToConsole(e);
            }
        };

        function logErrorToConsole(err) {
            try {
                if (err === undefined) {
                    return;
                }

                if (console === undefined) {
                    return;
                }

                if (console.error === undefined) {
                    return;
                }

                var smalldateTime = new Date().toSmallDateTime();
                var msg = "[" + smalldateTime + "] ";

                if (err.functionName) {
                    msg += "[function: " + err.functionName + "] ";
                }

                if (err.callerName) {
                    msg += "[caller name: " + err.callerName + "] ";
                }

                if (err.message) {
                    msg += err.message;
                }

                if (err.info) {
                    msg += '\n' + err.info;
                }

                //if (err.callerCode) {
                //    msg += "\n[caller code: " + err.callerCode + "] ";
                //}

                console.error(msg);

            } catch (e) {
                logExceptionToConsole(e);
            }
        }

        vpGrid.logError = function (err) {
            /// <signature>
            /// <summary>Log application error on all configured output devices (Console, Remote Server, custom DOM element</summary>
            /// <param name="err" type="Object">literal object that is like { message : "xxx", functionName : "yyy", info : "ttt" }</param>
            /// </signature>
            try {
                // try find caller
                try {
                    var caller = vpGrid.logError.caller;
                    var callerName = caller.name.toString();
                    var callerCode = caller.toString();
                    err.callerName = callerName;
                    err.callerCode = callerCode;

                } catch (e) {

                }

                logErrorToConsole(err);

                //TODO : remote logging

                //TODO : log inside specific DOM element

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function logAjaxErrorToConsole(xhr, statusMessage, errorMessage) {
            try {
                if (xhr === undefined) {
                    return;
                }

                if (console === undefined) {
                    return;
                }

                if (console.error === undefined) {
                    return;
                }

                var smalldateTime = new Date().toSmallDateTime();
                var msg = "[" + smalldateTime + "] ";
                if (statusMessage) {
                    msg += statusMessage;
                }

                if (errorMessage) {
                    msg += "; " + errorMessage;
                }

                msg += "; " + ajaxHttpStatusCodeInfo(xhr.status);

                if (xhr.requestURL) {
                    msg += "; requested URL is :" + xhr.requestURL;
                }

                console.error(msg);

            } catch (e) {
                //TODO : log
                var msg = e.message;
            }
        };

        function logAjaxError(xhr, statusMessage, errorMessage) {
            try {
                logAjaxErrorToConsole(xhr, statusMessage, errorMessage);

                //TODO : remote logging

                //TODO : log inside specific DOM element

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function ajaxHttpStatusCodeInfo(statusCode) {
            try {
                if (isNullOrUndefined(statusCode)) {
                    return "";
                }

                var statusErrorMap = {
                    0: "Cross Domain call is rejected by the browser (see CORS configuration)",
                    400: "Server understood the request but request content was invalid.",
                    401: "Unauthorised access.",
                    403: "Forbidden resouce can't be accessed",
                    404: "The url used is not recognized by the server. Please check Url",
                    500: "Internal Server Error.",
                    503: "Service Unavailable"
                };
                var message = "Http status code : " + statusCode + "; ";
                if (statusCode in statusErrorMap) {
                    message += statusErrorMap[statusCode];
                }
                return message;

            } catch (e) {
                vpGrid.logException(e);
                return "";
            }
        };

        function logServerError(response, details, element) {
            try {
                if (isNullOrUndefined(response)) {
                    //TODO : log
                    return;
                }

                var errorMessage = "";
                if (isNotNullOrUndefinedOrEmpty(response.errorMessage)) {
                    errorMessage = response.errorMessage;
                }

                var detailsMessage = "";
                if (isNotNullOrUndefinedOrEmpty(details)) {
                    detailsMessage = details;
                }

                var domHTML = outerHtml(element);

                var message = "Server Error : " + errorMessage + "; " + detailsMessage + "; on element: \n" + domHTML;
                vpGrid.logError({ message: message });

            } catch (e) {
                vpGrid.logException(e);
            }
        };
        // end trace API


        // Javascript Types Extensions
        //TODO : check if prototypes already exist
        //Date extensions
        (function () {
            try {
                var test = new Date();
                if (test.toSmallDateTime) {
                    vpGrid.logError({
                        message: "Date.prototype.toSmallDateTime is already defined. Check that vpGrid is not loaded twice or that any third-party JavaScript library has already defined this method."
                    });
                    return;
                }

                Date.prototype.toSmallDateTime = function () {
                    try {
                        /// <signature>
                        /// <summary>Get the input date in the following format : 'yyyy/mm/dd hh:mm:ss'</summary>
                        /// <returns type="String">Returns the formated date. If something goes wrong an empty string is returned.</returns>
                        /// </signature>
                        var dd = this.getDate();
                        var mm = this.getMonth() + 1;
                        var yyyy = this.getFullYear();
                        var hh = this.getHours();
                        var mn = this.getMinutes();
                        var ss = this.getSeconds();

                        if (dd < 10) {
                            dd = '0' + dd;
                        }
                        if (mm < 10) {
                            mm = '0' + mm;
                        }

                        if (hh < 10) {
                            hh = '0' + hh;
                        }

                        if (mn < 10) {
                            mn = '0' + mn;
                        }

                        if (ss < 10) {
                            ss = '0' + ss;
                        }

                        var now = yyyy + '/' + mm + '/' + dd + ' ' + hh + ':' + mn + ':' + ss;
                        return now;

                    } catch (e) {
                        vpGrid.logException(e);
                        return "";
                    }
                };


                if (test.year) {
                    vpGrid.logError({
                        message: "Date.prototype.year is already defined. Check that vpGrid is not loaded twice or that any third-party JavaScript library has already defined this method."
                    });
                    return;
                }
                Date.prototype.year = function () {
                    try {
                        /// <signature>
                        /// <summary>Get the year of input date.</summary>
                        /// <returns type="Number">Returns the year as a Number. If something goes wrong, NaN is returned.</returns>
                        /// </signature>
                        var yyyy = this.getFullYear();

                        var now = yyyy;
                        return now;

                    } catch (e) {
                        //TODO : log
                        vpGrid.logException(e);
                        return NaN;
                    }
                };


            } catch (e) {
                vpGrid.logException(e);
            }
        })();


        //Number extensions
        (function () {
            try {
                var test = 123.00;
                if (test.isGreaterThan) {
                    vpGrid.logError({
                        message: "Number.prototype.isGreaterThan is already defined. Check that vpGrid is not loaded twice or that any third-party JavaScript library has already defined this method."
                    });
                    return;
                }

                Number.prototype.isGreaterThan = function (value) {
                    try {
                        /// <signature>
                        /// <summary>Check if the input number is greater than value.</summary>
                        /// <param name="value" type="Number">Value to be compared to.</param>
                        /// <returns type="Boolean">Returns true if input number is > value.</returns>
                        /// </signature>

                        if (isNotNumber(value)) {
                            return false;
                        }

                        if (this > value) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                };


                if (test.isLowerThan) {
                    vpGrid.logError({
                        message: "Number.prototype.isLowerThan is already defined. Check that vpGrid is not loaded twice or that any third-party JavaScript library has already defined this method."
                    });
                    return;
                }

                Number.prototype.isLowerThan = function (value) {
                    try {
                        /// <signature>
                        /// <summary>Check if the input number is lower than value.</summary>
                        /// <param name="value" type="Number">Value to be compared to.</param>
                        /// <returns type="Boolean">Returns true if input number is < value.</returns>
                        /// </signature>

                        if (isNotNumber(value)) {
                            return false;
                        }

                        if (this < value) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                };

                //hack
                Number.prototype.toFloat = function () {
                    return this;
                }

            } catch (e) {
                vpGrid.logException(e);
            }
        })();

        //Array extensions
        Array.prototype.toUnique = function () {
            try {

                if (this.length === 0) {
                    return this;
                }

                if (this.length === 1) {
                    return this;
                }


                var result = [], map = {}, item;
                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    item = this[i];
                    if (!map[item]) {
                        result.push(item);
                        map[item] = true;
                    }
                }

                return result;


            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        Array.prototype.removeEmptyEntries = function () {
            try {

                if (this.length === 0) {
                    return this;
                }

                var result = [];
                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];
                    if (isNotNullOrUndefinedOrEmpty(item)) {
                        result.push(item);
                    }
                }

                return result;

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        Array.prototype.clear = function () {
            try {

                if (this.length === 0) {
                    return this;
                }

                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    this.shift();
                }

                return this;

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        Array.prototype.pushOnce = function (input) {
            try {

                if (isNullOrUndefinedOrEmpty(input)) {
                    //TODO : log
                    return;
                }

                if (this.length === 0) {
                    this.push(input);
                    return;
                }

                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];
                    if (item === input) {
                        return;
                    }
                }
                this.push(input);

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        Array.prototype.insertOnce = function (input) {
            try {

                if (isNullOrUndefinedOrEmpty(input)) {
                    //TODO : log
                    return;
                }

                if (this.length === 0) {
                    this.push(input);
                    return;
                }

                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];
                    if (item === input) {
                        return;
                    }
                }
                this.splice(0,0,input);

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        Array.prototype.isEmpty = function () {
            try {

                if (this.length === 0) {
                    return true;
                }

                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];
                    if (isNotNullOrUndefinedOrEmpty(item)) {
                        return false;
                    }
                }

                return true;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        Array.prototype.getValueOfKey = function (keyName) {
            /// <signature>
            /// <summary>Get the value of the input key.The array must be a collection of key/value pairs : [ {key:xxx,value:yyy}, ...]</summary>
            /// <param name="keyName" type="String">Value of the key to search in the dictionnary</param>
            /// <returns type="Object">Returns the content of the value property when the key is found. If key not found it returns undefined.</returns>
            /// </signature>
            try {

                if (this.length === 0) {
                    return undefined;
                }

                if (isNotString(keyName)) {
                    vpGrid.logError({
                        functionName: "getValueOfKey",
                        message: "input keyName is not a valid string."
                    });
                    return undefined;
                }

                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];

                    var key = item.key;
                    if (key === keyName) {
                        return item.value;
                    }

                }

                return undefined;

            } catch (e) {
                vpGrid.logException(e);
                return undefined;
            }
        };

        Array.prototype.addRangeOfIntegers = function (minValue, maxValue) {
            /// <signature>
            /// <summary>Adds a ranges of consecutive integers in the input array.</summary>
            /// <param name="minValue" type="Int">Start integer value to add in the array.</param>
            /// <param name="maxValue" type="Int">Last integer value to add in the array.</param>
            /// <returns type="Array">Returns input array filled with input values starting from minValue up to maxValue.</returns>
            /// </signature>
            try {
                if (isNotInt(minValue)) {
                    //TODO : log
                    return;
                }

                if (isNotInt(maxValue)) {
                    //TODO : log
                    return;
                }

                if (minValue === maxValue) {
                    this.push(minValue);
                    return;
                }

                if (minValue > maxValue) {
                    //TODO : log
                    return;
                }


                for (var i = minValue; i <= maxValue; i++) {
                    this.push(i);
                }

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        Array.prototype.sum = function () {
            /// <signature>
            /// <summary>Compute the sum of all items in input array.Each item in this array may be a number or maybe a string.</summary>
            /// <returns type="Number">Returns the sum of all items in the array. Returns zero if something goes wrong.</returns>
            /// </signature>
            try {
                var sum = 0;
                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];
                    if (isNotNumber(item)) {
                        continue;
                    }
                    var itemValue = item.toFloat();

                    if (isNaN(itemValue)) {
                        continue;
                    }
                    sum += itemValue;
                }
                

                return sum;

            } catch (e) {
                vpGrid.logException(e);
                return 0;
            }
        };

        Array.prototype.minus = function (input) {
            /// <signature>
            /// <summary>Compute the difference of all items between this array and input array.Each item in both arrays may be a number or maybe a string.</summary>
            /// <param name="input" type="Array">Right operand of the minus operation. Shaould be an array of same size as this array.</param>
            /// <returns type="Array">Returns anew array that contains the difference of all items. Returns zero if something goes wrong.</returns>
            /// </signature>
            try {
                var diffArray = [];
                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item1 = this[i];
                    var item2 = input[i];
                    if (isNotNumber(item1)) {
                        diffArray.push(NaN);
                        continue;
                    }
                    if (isNotNumber(item2)) {
                        diffArray.push(NaN);
                        continue;
                    }
                    var item1Value = item1.toFloat();
                    var item2Value = item2.toFloat();

                    if (isNaN(item1Value)) {
                        diffArray.push(NaN);
                        continue;
                    }

                    if (isNaN(item2Value)) {
                        diffArray.push(NaN);
                        continue;
                    }
                    diffArray.push(item1Value - item2Value);
                }


                return diffArray;

            } catch (e) {
                vpGrid.logException(e);
                return [];
            }
        };

        Array.prototype.duplicate = function (input) {
            /// <signature>
            /// <summary>Duplicate input array.</summary>
            /// <param name="input" type="Array">Array to be duplicated</param>
            /// <returns type="Array">Returns a new array that is a copy of input array.</returns>
            /// </signature>
            try {
                var duplicatedArray = [];
                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];
                    var duplicatedItem = item;
                    //TODO : make a copy of item1 if it is a lietarl object

                    duplicatedArray.push(duplicatedItem);
                }

                return duplicatedArray;

            } catch (e) {
                vpGrid.logException(e);
                return [];
            }
        };

        Array.prototype.hasAnObjectWithPropertyAndValue = function (propertyName, propertyValue) {
            /// <signature>
            /// <summary>Check if the input array contains an object with a property called propertyName that has a value equals to propertyValue.
            ///          The array must be a collection of literal objects.
            /// </summary>
            /// <param name="propertyName" type="String">Name of the property to search within the objects contained in the input array.</param>
            /// <param name="propertyValue" type="Object">Value of the property to search in the array.</param>
            /// <returns type="Boolean">Returns true when an object is found. Returns false otherwise.</returns>
            /// </signature>
            try {

                if (this.length === 0) {
                    return false;
                }

                if (isNotString(propertyName)) {
                    vpGrid.logError({
                        functionName: "hasAnObjectWithPropertyAndValue",
                        message: "input propertyName is not a valid string : '" + propertyName + "'"
                    });
                    return false;
                }


                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];

                    if (!item.hasOwnProperty(propertyName)) {
                        continue;
                    }
                    
                    var value = item[propertyName];
                    if (value === propertyValue) {
                        return true;
                    }

                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        Array.prototype.removeAllObjectsWithPropertyAndValue = function (propertyName, propertyValue) {
            /// <signature>
            /// <summary>Remove from the input array any object with a property called propertyName that has a value equals to propertyValue.
            ///          The array must be a collection of literal objects.
            /// </summary>
            /// <param name="propertyName" type="String">Name of the property to search within the objects contained in the input array.</param>
            /// <param name="propertyValue" type="Object">Value of the property to search in the array.</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {

                if (this.length === 0) {
                    return ;
                }

                if (isNotString(propertyName)) {
                    vpGrid.logError({
                        functionName: "removeAllObjectsWithPropertyAndValue",
                        message: "input propertyName is not a valid string : '" + propertyName + "'"
                    });
                    return false;
                }


                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];

                    if (!item.hasOwnProperty(propertyName)) {
                        continue;
                    }

                    var value = item[propertyName];
                    if (value === propertyValue) {
                        this.splice(i, 1);
                        //start again to loop
                        i = -1;
                        itemCount -= 1;
                    }

                }


            } catch (e) {
                vpGrid.logException(e);

            }
        };

        Array.prototype.addArray = function (input) {
            try {
                if (isNullOrUndefinedOrEmpty(input)) {
                    return this;
                }

                var itemCount = input.length;
                for (var i = 0; i < itemCount; i++) {
                    this.push(input[i]);
                }

                return this;

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        // end Array extensions



        //String extensions
        String.prototype.isString = function () {
            return true;
        };

        String.prototype.isNullOrEmpty = function () {
            try {
                if (this === null) {
                    return true;
                }

                if (this === undefined) {
                    return true;
                }

                if (this.length === undefined) {
                    return true;
                }

                if (this.length === 0) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.isNullOrEmptyOrWhitespace = function () {
            try {
                if (this === null) {
                    return true;
                }

                if (this === undefined) {
                    return true;
                }

                if (this.length === undefined) {
                    return true;
                }

                if (this.length === 0) {
                    return true;
                }

                if (this.trim === undefined) {
                    String.prototype.trim = function () {
                        try {
                            var s = this + '';
                            s = s.replace(/^\s+|\s+$/g, '');
                            s = s.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
                            s = s.replace(/(^(\&nbsp\;)+)|((\&nbsp\;)+$)/g, '');
                            s = s.replace(/(^(\&#160\;)+)|((\&#160\;)+$)/g, '');
                            return s;

                        } catch (e) {
                            vpGrid.logException(e);
                            return this;
                        }
                    };
                }

                var trimedInput = this.trim();

                if (trimedInput === null) {
                    return true;
                }

                if (trimedInput === undefined) {
                    return true;
                }

                if (trimedInput.length === undefined) {
                    return true;
                }

                if (trimedInput.length === 0) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.isNotNullOrEmptyOrWhitespace = function () {
            return this.isNullOrEmptyOrWhitespace() === false;
        };

        String.prototype.toEncodedSymbols = function () {
            try {

                if (this.isNullOrEmptyOrWhitespace()) {
                    return "";
                }

                var encoded = this.replace("ô", "&#244;");
                return encoded;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return this;
            }
        };

        String.prototype.toEncodedHTML = function () {
            try {

                if (this.isNullOrEmptyOrWhitespace()) {
                    return "";
                }

                var htmlEncodedInput = $('<div/>').text(this).html();
                //htmlEncodedInput = htmlEncodedInput.toEncodedSymbols();

                return htmlEncodedInput;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return this;
            }
        };

        String.prototype.toArray = function (splitter) {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return [];
                }
                if (isNullOrUndefinedOrEmpty(splitter)) {
                    splitter = ",";
                }

                var splittedArray = this.split(splitter);

                if (isNullOrUndefinedOrEmpty(splittedArray)) {
                    return [];
                }

                // trim every item and remove empty items
                var itemCount = splittedArray.length;
                var normalizedArray = [];
                for (var i = 0; i < itemCount; i++) {
                    var item = splittedArray[i];
                    item = $.trim(item);

                    if (isNotString(item)) {
                        continue;
                    }

                    if (item.isNullOrEmptyOrWhitespace()) {
                        continue;
                    }
                    normalizedArray.push(item);
                }

                return normalizedArray;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return [];
            }
        };

        String.prototype.toInt = function () {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return NaN;
                }

                var intValue = parseInt(this, 10);

                return intValue;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return NaN;
            }
        };

        String.prototype.isInt = function () {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return false;
                }

                if (isNaN(this)) {
                    return false;
                }
                //TODO : remove all spaces
                //TODO : check for non numeric characters

                return true;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.isFloat = function () {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return false;
                }

                if (isNaN(this)) {
                    return false;
                }

                return true;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.toFloat = function () {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return NaN;
                }

                var floatValue = parseFloat(this);

                return floatValue;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return NaN;
            }
        };

        String.prototype.multipliedBy = function (value) {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return NaN;
                }

                if (isNotNumber(value)) {
                    return NaN;
                }

                if (isNotNumber(this)) {
                    return NaN;
                }

                var val1 = this.toFloat();
                var val2 = value;
                if (val2.toFloat) {
                    val2 = val2.toFloat();
                }

                var result = val1 * val2;
                return result;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return NaN;
            }
        };

        String.prototype.startsWith = function (prefix) {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return false;
                }

                if (isNotString(prefix)) {
                    return false;
                }

                if (prefix.length > this.length) {
                    return false;
                }

                var thisPrefix = this.substring(0, prefix.length);
                if (thisPrefix === prefix) {
                    return true;
                }

                return false;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.removePrefix = function (prefix) {
            try {

                if (this.isNullOrEmptyOrWhitespace()) {
                    return "";
                }

                if (isNotString(prefix)) {
                    return this;
                }

                if (prefix.isNullOrEmptyOrWhitespace()) {
                    return this;
                }

                if (prefix.length > this.length) {
                    return this;
                }

                if (this.startsWith(prefix)) {
                    var result = this.substring(prefix.length);
                    return result;
                }

                return this;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return this;
            }
        };

        String.prototype.contains = function (search) {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return false;
                }

                if (isNotString(search)) {
                    return false;
                }

                if (search.length > this.length) {
                    return false;
                }

                var index = this.indexOf(search);
                if (index !== -1) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.doesNotContain = function (search) {
            return this.contains(search) === false;
        };

        String.prototype.isInArray = function (inputArray) {
            try {

                if (this.isNullOrEmptyOrWhitespace()) {
                    return false;
                }

                if (isNotArray(inputArray)) {
                    return false;
                }

                var itemCount = inputArray.length;

                if (itemCount === 0) {
                    return false;
                }

                var thisValue = this.toString();

                for (var i = 0; i < itemCount; i++) {
                    if (inputArray[i] === thisValue) {
                        return true;
                    }

                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.isNotInArray = function (inputArray) {
            return this.isInArray(inputArray) === false;
        };

        String.prototype.replaceAll = function (stringToSearch, stringToReplace) {
            try {

                if (this.isNullOrEmptyOrWhitespace()) {
                    return "";
                }

                if (isNotString(stringToSearch)) {
                    return this;
                }

                if (isNotString(stringToReplace)) {
                    return this;
                }

                if (stringToSearch.isNullOrEmpty()) {
                    return this;
                }

                if (stringToSearch.length > this.length) {
                    return this;
                }

                var result = this;
                var length0 = result.length;
                for (var i = 0; i < 100; i++) {
                    if (result.doesNotContain(stringToSearch)) {
                        return result.toString();
                    }
                    result = result.replace(stringToSearch, stringToReplace);
                    var length = result.length;
                    if (length === length0) {
                        return result.toString();
                    }

                    length0 = length;
                }

                return this;

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        String.prototype.leafName = function () {
            /// <signature>
            /// <summary>Get the leaf name on a string that represents an Url</summary>
            /// </signature>
            try {

                if (this.isNullOrEmptyOrWhitespace()) {
                    return "";
                }

                var inputArray = this.toArray("/");
                if (isNullOrUndefinedOrEmpty(inputArray)) {
                    return this;
                }

                var leafName = inputArray.pop();

                return leafName;

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        String.prototype.isCustomPropertyOf = function (input) {
            /// <signature>
            /// <summary>Checks if this string is the name of an existing custom property within input object </summary>
            /// <param name="input" type="Object">Object in which to search for the custom property.</param>
            /// <returns type="Boolean">Returns true if a custom property with the same name exists in the input object.</returns>
            /// </signature>
            try {

                if (input === null) {
                    return false;
                }

                if (input === undefined) {
                    return false;
                }

                if (input.hasOwnProperty === undefined) {
                    return false;
                }

                if (typeof input.hasOwnProperty !== "function") {
                    return false;
                }

                if (input.hasOwnProperty(this)) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.isNotCustomPropertyOf = function (input) {
            return this.isCustomPropertyOf(input) === false;
        };

        // end Javascript Types Extensions

        // jQuery extensions
        $.fn.extend({
            isNot: function (selector) {
                return this.is(selector) === false;
            }
        });

        $.fn.extend({
            notFound: function () {
                try {
                    if (this === null) {
                        return true;
                    }

                    if (this === undefined) {
                        return true;
                    }

                    if (this.length === undefined) {
                        return true;
                    }

                    if (this.length === 0) {
                        return true;
                    }

                    return false;

                } catch (e) {
                    //TODO : log
                    vpGrid.logException(e);
                    return false;
                }
            }
        });

        $.fn.extend({
            found: function () {
                try {
                    if (this === null) {
                        return false;
                    }

                    if (this === undefined) {
                        return false;
                    }

                    if (this.length === undefined) {
                        return false;
                    }

                    if (this.length === 0) {
                        return false;
                    }

                    return true;

                } catch (e) {
                    //TODO : log
                    vpGrid.logException(e);
                    return false;
                }
            }
        });

        $.fn.extend({
            isCheckbox: function () {
                try {
                    if (this.notFound()) {
                        return false;
                    }

                    if (this.is(':checkbox')) {
                        return true;
                    }

                    return false;

                } catch (e) {
                    vpGrid.logException(e);
                    return false;
                }
            }
        });

        $.fn.extend({
            isNotCheckbox: function () {
                return this.isCheckbox() === false;
            }
        });


        $.fn.extend({
            isUncheked: function () {
                try {
                    if (this.notFound()) {
                        return true;
                    }

                    if (this.is(':checked')) {
                        return true;
                    }

                    return false;

                } catch (e) {
                    vpGrid.logException(e);
                    return false;
                }
            }
        });

        $.fn.extend({
            isInputText: function () {
                try {
                    if (this.notFound()) {
                        return false;
                    }

                    if (this.is('input:text')) {
                        return true;
                    }

                    if (this.is('input:password')) {
                        return true;
                    }

                    //if (this.is('input:email')) {
                    //    return true;
                    //}

                    return false;

                } catch (e) {
                    vpGrid.logException(e);
                    return false;
                }
            }
        });

        $.fn.extend({
            toBooleanOrDefaultFromAttribute: function (attributeName, defaultValue) {
                try {
                    if (this === null) {
                        return defaultValue;
                    }

                    if (this === undefined) {
                        return defaultValue;
                    }

                    if (this.length === undefined) {
                        return defaultValue;
                    }

                    if (this.length === 0) {
                        return defaultValue;
                    }

                    if (isNotString(attributeName)) {
                        return defaultValue;
                    }

                    var attributeValue = this.attr(attributeName);
                    if (isNullOrUndefinedOrEmpty(attributeValue)) {
                        return defaultValue;
                    }

                    if (isNotString(attributeValue)) {
                        return defaultValue;
                    }

                    attributeValue = attributeValue.trim();

                    if (attributeValue.isNullOrEmptyOrWhitespace()) {
                        return defaultValue;
                    }

                    if (attributeValue === "true") {
                        return true;
                    }

                    return false;

                } catch (e) {
                    vpGrid.logException(e);
                    return defaultValue;
                }
            }
        });

        $.fn.extend({
            toIntOrDefaultFromAttribute: function (attributeName, defaultValue) {
                /// <signature>
                /// <summary>Get the attribute value as an integer</summary>
                /// <param name="attributeName" type="String">Name of the tag attribute</param>
                /// <param name="defaultValue" type="Number">Value to return if attribute is not found or is not in valid format</param>
                /// <returns type="Number">Returns the found attribute value or the defaultValue if attribute is not found or its value is not valid.</returns>
                /// </signature>
                try {
                    if (this === null) {
                        return defaultValue;
                    }

                    if (this === undefined) {
                        return defaultValue;
                    }

                    if (this.length === undefined) {
                        return defaultValue;
                    }

                    if (this.length === 0) {
                        return defaultValue;
                    }

                    if (isNotString(attributeName)) {
                        return defaultValue;
                    }

                    var attributeValue = this.attr(attributeName);
                    if (isNullOrUndefinedOrEmpty(attributeValue)) {
                        return defaultValue;
                    }

                    if (isNotString(attributeValue)) {
                        return defaultValue;
                    }

                    if (isNotNumber(attributeValue)) {
                        return defaultValue;
                    }

                    var intValue = attributeValue.toInt();

                    return intValue;

                } catch (e) {
                    vpGrid.logException(e);
                    return defaultValue;
                }
            }
        });

        $.fn.extend({
            toStringOrDefaultFromAttribute: function (attributeName, defaultValue) {
                try {
                    if (this === null) {
                        return defaultValue;
                    }

                    if (this === undefined) {
                        return defaultValue;
                    }

                    if (this.length === undefined) {
                        return defaultValue;
                    }

                    if (this.length === 0) {
                        return defaultValue;
                    }

                    if (isNotString(attributeName)) {
                        return defaultValue;
                    }

                    var attributeValue = this.attr(attributeName);
                    if (isNotString(attributeValue)) {
                        return defaultValue;
                    }

                    //trim the value;
                    attributeValue = attributeValue.trim();

                    if (attributeValue.isNullOrEmptyOrWhitespace()) {
                        return defaultValue;
                    }

                    return attributeValue;

                } catch (e) {
                    vpGrid.logException(e);
                    return defaultValue;
                }
            }
        });

        $.fn.extend({
            toEncodedHTML: function () {
                return this.each(function () {
                    try {

                        var jqElement = $(this);

                        // get the text inside this HTML tag
                        var rawText = jqElement.text();
                        var encodedText = rawText.toEncodedHTML();
                        jqElement.html(encodedText);

                    } catch (e) {
                        //TODO : log
                        vpGrid.logException(e);

                    }
                });

            }
        });

        $.fn.extend({
            hideEx: function () {
                return this.each(function () {
                    try {
                        var jqElement = $(this);

                        // apply css class that will hide the element
                        jqElement.addClass("vpgrid-hidden");

                        if (jqElement.is("option")) {
                            jqElement.attr('disabled', 'true');

                            //TODO : backup current selected option in select tag

                            jqElement.removeAttr("selected");
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }

                });
            }
        });

        $.fn.extend({
            showEx: function () {
                return this.each(function () {
                    try {
                        var jqElement = $(this);

                        // apply css class that will hide the element
                        jqElement.removeClass("vpgrid-hidden");

                        if (jqElement.is("option")) {
                            jqElement.removeAttr('disabled');
                            // TODO : restore current selected option in select tag
                        }


                    } catch (e) {
                        //TODO : log
                        vpGrid.logException(e);

                    }

                });
            }
        });

        $.fn.extend({
            saveOriginalClassAttributeContent: function () {
                return this.each(function () {
                    try {
                        var jqElement = $(this);

                        if (jqElement.notFound()) {
                            vpGrid.logError({
                                functionName: "saveOriginalClassAttributeContent",
                                message: "Selector not found : " + jqElement.selector
                            });
                            return;
                        }

                        var originalContent = jqElement.toStringOrDefaultFromAttribute(
                                    vpGrid.HtmlDataTag.OriginalClassAttributeContent,
                                    "");

                        if (originalContent.isNotNullOrEmptyOrWhitespace()) {
                            // the save operation has already been done
                            return;
                        }

                        var classAttributeContent = jqElement.toStringOrDefaultFromAttribute("class", "");
                        if (classAttributeContent.isNullOrEmptyOrWhitespace()) {
                            classAttributeContent = "_"; // special hack in case jqElement has no class attribute
                        }

                        jqElement.attr(vpGrid.HtmlDataTag.OriginalClassAttributeContent, classAttributeContent);

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                });
            }
        });

        $.fn.extend({
            restoreOriginalClassAttributeContent: function () {
                return this.each(function () {
                    try {
                        var jqElement = $(this);

                        if (jqElement.notFound()) {
                            vpGrid.logError({
                                functionName: "restoreOriginalClassAttributeContent",
                                message: "Selector not found : " + jqElement.selector
                            });
                            return;
                        }

                        var originalContent = jqElement.toStringOrDefaultFromAttribute(
                                    vpGrid.HtmlDataTag.OriginalClassAttributeContent,
                                    "");

                        jqElement.attr("class", originalContent);

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                });
            }
        });

        $.fn.extend({
            openServerSideDialog: function (widthPercentage, heightPercentage) {
                /// <signature>
                /// <summary>Load an external url within an iframe as a modal pop-up. The iframe is wrapped in a jQuery-ui widget dialog modal window.</summary>
                /// <param name="widthPercentage" type="Number">width of the iframe expressed as a percentage of the current browser window width. The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9</param>
                /// <param name="heightPercentage" type="Number">height of the iframe expressed as a percentage of the current browser window height. The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9</param>
                /// </signature>
                try {
                    var jqElement = $(this);
                    if (jqElement.notFound()) {
                        vpGrid.logError({
                            message: "selector not found : " + jqElement.selector,
                            functionName: "openServerSideDialog"
                        });
                        return;
                    }

                    var windowSize = {
                        width: $(window).width(),
                        height: $(window).height()
                    };

                    //get the iframe url:
                    var iframeUrl = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.Url, "");

                    if (iframeUrl.isNullOrEmptyOrWhitespace()) {
                        
                        vpGrid.logError({
                            functionName: "openServerSideDialog",
                            message: "data attribute : " + vpGrid.HtmlDataTag.Url + " is not defined on element : \n" + outerHtml(jqElement[0])
                        });
                        return;
                    }

                    //get input parameters
                    var widthCoeff = 0.9;
                    if (isNumber(widthPercentage)) {
                        widthCoeff = widthPercentage;
                    }

                    var heightCoeff = 0.9;
                    if (isNumber(heightPercentage)) {
                        heightCoeff = heightPercentage;
                    }

                    var iframe = $('<iframe>', {
                        frameborder: 0,
                        scrolling: 'no',
                        width: windowSize.width * widthCoeff,
                        height: windowSize.height * heightCoeff,
                        src: iframeUrl
                    });

                    //change the dialog options
                    jqElement.dialog('option', {
                        width: "auto",
                        height: "auto"
                    });

                    // set custom title if needed
                    jqElement.setCustomTitleOnThisDialog();

                    //empty current content of the dialog
                    jqElement.html("");

                    iframe.appendTo(jqElement);
                    jqElement.dialog('open');

                } catch (e) {
                    vpGrid.logException(e);

                }
            }
        });

        $.fn.extend({
            openClientSideDialog: function (position, widthPercentage, heightPercentage) {
                /// <signature>
                /// <summary>Open a jQuery-ui widget dialog modal window.</summary>
                /// <param name="widthPercentage" type="Number">width of the iframe expressed as a percentage of the current browser window width. The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9</param>
                /// <param name="heightPercentage" type="Number">height of the iframe expressed as a percentage of the current browser window height. The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9</param>
                /// </signature>
                try {
                    var jqElement = $(this);
                    if (jqElement.notFound()) {
                        vpGrid.logError({
                            message: "selector not found : " + jqElement.selector,
                            functionName: "openServerSideDialog"
                        });
                        return;
                    }

                    var windowSize = {
                        width: $(window).width(),
                        height: $(window).height()
                    };

                    //get input parameters
                    var widthCoeff = 0.9;
                    if (isNumber(widthPercentage)) {
                        widthCoeff = widthPercentage;
                    }

                    var heightCoeff = 0.9;
                    if (isNumber(heightCoeff)) {
                        heightCoeff = heightPercentage;
                    }

                    //change the dialog options
                    jqElement.dialog('option', {
                        width: "auto",
                        height: "auto"
                    });

                    if (isNotNullOrUndefinedOrEmpty(position)) {
                        jqElement.dialog('option', 'position', position);
                    }

                    // set custom title if needed
                    jqElement.setCustomTitleOnThisDialog();

                    // reset all validation error messages coming from previous usage
                    jqElement.resetValidationErrors();

                    //Reset input fields in this dialog
                    jqElement.resetInputFields();

                    // Set automatic validation
                    jqElement.autoValidateThisForm();

                    //raise event onModalDialogOpening to enable listeners do processing on the dialog before it is shown on screen
                    var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, '');
                    var eventArgs0 = {
                        dialogId: dialogId,
                        rowData : undefined,
                        dialogData: undefined, //TODO : fill dialog Data
                        cancel: false,
                        cancelReason: ""
                    };
                    onModalDialogOpening(this, eventArgs0);
                    //TODO : check if eventArgs.cancel === true

                    jqElement.dialog('open');

                    //raise event onModalDialogOpened to enable listeners do additional processing on the dialog
                    //var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, '');
                    var eventArgs = {
                        dialogId: dialogId,
                        rowData: undefined,
                        dialogData: undefined //TODO : fill dialog Data
                    };
                    onModalDialogOpened(this, eventArgs);

                } catch (e) {
                    vpGrid.logException(e);

                }
            }
        });

        $.fn.extend({
            setCustomTitleOnThisDialog: function (dataRow, raiseErrorOnNotFound) {
                /// <signature>
                /// <summary>Customize the title of the jQuery-ui widget dialog modal window.
                /// </summary>
                /// <param name="dataRow" type="Object">Literal object that represents an item in the grid. 
                ///         The properties of this object must match the data-vpgrid-column-name value defined by the column schema section of the web page
                /// </param>
                /// <param name="raiseErrorOnNotFound" type="Boolean">If true and no HTLM element with the data attribute data-vpgrid-column-name has been found then an error is raised. </param>
                /// </signature>
                try {
                    var jqElement = $(this);
                    if (jqElement.notFound()) {
                        vpGrid.logError({
                            message: "selector not found : " + jqElement.selector,
                            functionName: "setCustomTitleOnThisDialog"
                        });
                        return;
                    }

                    // find the default title of the current dialog window
                    var jqTitlebarContent = jqElement.closest('div.ui-dialog').find('div.ui-dialog-titlebar span.ui-dialog-title');
                    
                    if (jqTitlebarContent.notFound() ) {
                        vpGrid.logError({
                            message: "Selector not found : '" + jqTitlebarContent.selector + "'",
                            functionName: "setCustomTitleOnThisDialog",
                            info: "The title cannot be modified on modal dialog element : \n" + outerHtml(jqElement[0])

                        });
                    }

                    // check if there is custom content to inject in the title bar
                    var customTitleSelector = "div[role=" + vpGrid.HtmlRoleAttribute.Titlebar + "]";
                    var customTitle = jqElement.find(customTitleSelector);


                    if (customTitle.notFound()) {
                        //the title content has been moved from its original place in the DOM when the above code has run one time
                        customTitle = jqElement.closest('div.ui-dialog').find(customTitleSelector);
                    }

                    if (customTitle.notFound() && raiseErrorOnNotFound === true) {
                        vpGrid.logError({
                            message: "Selector not found : '" + customTitle.selector + "'",
                            functionName: "setCustomTitleOnThisDialog",
                            info: "Custom title is missing on modal dialog element : \n" + outerHtml(jqElement[0])

                        });
                    }

                    if (customTitle.notFound()) {
                        //do not modify standard ui-dialog title bar
                        return this;
                    }

                    //swap default dialog title with the custom one
                    customTitle.detach();
                    jqTitlebarContent.html("");
                    customTitle.appendTo(jqTitlebarContent);

                    if (isNotNullOrUndefinedOrEmpty(dataRow)) {
                        customTitle.fillWithDataRow(dataRow, raiseErrorOnNotFound);
                    }
                    
                    customTitle.removeClass("vpgrid-hidden");

                    // add special class to select element so that it is selectable
                    customTitle.find('select').addClass('ui-dialog-content');

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }
            }
        });

        
        $.fn.extend({
            openClientSideDialogWithSelectedItem: function (position, widthPercentage, heightPercentage) {
                /// <signature>
                /// <summary>Open a jQuery-ui widget dialog modal window.
                ///         Input controls on this dialog are filled with the data coming from the selected item in the grid.
                ///         The databinding is done through the data-tag attribute : data-vpgrid-column-name
                ///</summary>
                /// <param name="widthPercentage" type="Number">width of the iframe expressed as a percentage of the current browser window width. The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9</param>
                /// <param name="heightPercentage" type="Number">height of the iframe expressed as a percentage of the current browser window height. The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9</param>
                /// </signature>
                try {
                    var jqElement = $(this);
                    if (jqElement.notFound()) {
                        vpGrid.logError({
                            message: "selector not found : " + jqElement.selector,
                            functionName: "openServerSideDialog"
                        });
                        return;
                    }

                    var windowSize = {
                        width: $(window).width(),
                        height: $(window).height()
                    };

                    //get input parameters
                    var widthCoeff = 0.9;
                    if (isNumber(widthPercentage)) {
                        widthCoeff = widthPercentage;
                    }

                    var heightCoeff = 0.9;
                    if (isNumber(heightPercentage)) {
                        heightCoeff = heightPercentage;
                    }

                    //change the dialog options
                    jqElement.dialog('option', {
                        width: "auto",
                        height: "auto"
                    });

                    if (isNotNullOrUndefinedOrEmpty(position)) {
                        jqElement.dialog('option', 'position', position);
                    }

                    // get the data row
                    var dataRow = JQGrid.selectedRowData();

                    // set custom title if needed
                    jqElement.setCustomTitleOnThisDialog(dataRow, true);

                    // check if the dialog contains a form element
                    // reset all validation error messages coming from previous usage
                    jqElement.resetValidationErrors();
                    jqElement.fillWithDataRow(dataRow);
                    jqElement.autoValidateThisForm();


                    //raise event onModalDialogOpening to enable listeners do processing on the dialog before it is shown on screen
                    var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, '');
                    var eventArgs0 = {
                        dialogId: dialogId,
                        rowData : dataRow,
                        dialogData: undefined, //TODO : fill dialog Data
                        cancel: false,
                        cancelReason : ""
                    };
                    onModalDialogOpening(this, eventArgs0);
                    //TODO : check if eventArgs.cancel === true

                    jqElement.dialog('open');

                    //raise event onModalDialogOpened to enable listeners do additional processing on the dialog
                    //var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, '');
                    var eventArgs = {
                        dialogId: dialogId,
                        rowData: dataRow,
                        dialogData: undefined  //TODO : fill dialog Data
                    };
                    onModalDialogOpened(this, eventArgs);

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }
            }
        });


        $.fn.extend({
            openServerSideDialogWithSelectedItem: function (position, sizeRatio) {
                /// <signature>
                /// <summary>Open a jQuery-ui widget dialog modal window that embeds an external web page in an iFrame.
                ///</summary>
                /// <param name="position" type="Object">jQuery-ui Position option object that configures initial position of the UI-Dialog</param>
                /// <param name="sizeRatio" type="Number">Size of the UI-Dialog expressed as a percentage of the current browser window size. 
                ///     The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9
                /// </param>
                /// </signature>
                try {
                    var jqElement = $(this);
                    if (jqElement.notFound()) {
                        vpGrid.logError({
                            message: "Selector not found : " + jqElement.selector,
                            functionName: "openServerSideDialogWithSelectedItem"
                        });
                        return;
                    }


                    //get the iframe url:
                    var iframeUrl = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.Url, "");

                    if (iframeUrl.isNullOrEmptyOrWhitespace()) {
                        vpGrid.logError({
                            functionName: "openServerSideDialogWithSelectedItem",
                            message: "data attribute : " + vpGrid.HtmlDataTag.Url + " is not defined on element : \n" + outerHtml(jqElement[0]),
                            info : "The UI Dialog is canceled. Check the configuration of the vpgrid data attributes on the above HTML."
                        });
                        return;
                    }
                    var windowSize = {
                        width: $(window).width(),
                        height: $(window).height()
                    };

                    //get input parameters
                    var coeff = 0.9;
                    if (isNumber(sizeRatio)) {
                        coeff = sizeRatio;
                    }

                    //TODO : check 0.1 < coeff < 0.9

                    //change the dialog options
                    jqElement.dialog('option', {
                        width: "auto",
                        height: "auto"
                    });

                    if (isNotNullOrUndefinedOrEmpty(position)) {
                        jqElement.dialog('option', 'position', position);
                    }

                    // get the data row
                    var dataRow = JQGrid.selectedRowData();

                    // set custom title if needed
                    jqElement.setCustomTitleOnThisDialog(dataRow, false);

                    //raise event onModalDialogOpening to enable listeners do processing on the dialog before it is shown on screen
                    var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, '');
                    var eventArgs0 = {
                        dialogId: dialogId,
                        rowData : dataRow,
                        dialogData: undefined, //TODO : fill dialog Data
                        cancel: false,
                        cancelReason: "",
                        iframeUrl: iframeUrl
                    };
                    onModalDialogOpening(this, eventArgs0);
                    //TODO : check if eventArgs.cancel === true

                    //dynamically create an iframe and load contents into it.
                    var iframe = $('<iframe>', {
                        frameborder: 0,
                        scrolling: 'no',
                        width: windowSize.width * coeff,
                        height: windowSize.height * coeff,
                        src: eventArgs0.iframeUrl
                    });

                    //change the dialog options
                    jqElement.dialog('option', {
                        width: "auto",
                        height: "auto"
                    });

                    //empty current content of the dialog
                    jqElement.html("");

                    iframe.appendTo(jqElement);

                    jqElement.dialog('open');

                    //raise event onModalDialogOpened to enable listeners do additional processing on the dialog
                    //var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, '');
                    var eventArgs = {
                        dialogId: dialogId,
                        rowData: dataRow,
                        dialogData: undefined //TODO : fill dialog Data
                    };
                    onModalDialogOpened(this, eventArgs);

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }
            }
        });

        $.fn.extend({
            fillWithDataRow: function (dataRow, raiseErrorOnNotFound) {
                /// <signature>
                /// <summary>Input controls and other html elements tagged are filled with the input jqGrid row data.
                ///         The databinding is done through the data-tag attribute : data-vpgrid-column-name
                ///</summary>
                /// <param name="dataRow" type="Object">Literal object. The properties of this object must match the data-vpgrid-column-name value </param>
                /// <param name="raiseErrorOnNotFound" type="Boolean">If true and no HTLM element with the data attribute data-vpgrid-column-name has been found then an error is raised. </param>

                /// </signature>
                try {
                    var jqElement = $(this);
                    if (jqElement.notFound()) {
                        vpGrid.logError({
                            message: "selector not found : " + jqElement.selector,
                            functionName: "fillWithRowData"
                        });
                        return;
                    }

                    if (isNullOrUndefinedOrEmpty(raiseErrorOnNotFound)) {
                        raiseErrorOnNotFound = true;
                    }

                    //fill input element from selected item
                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = jqElement.find(inputFieldSelector);

                    if (jqInputFields.notFound() && raiseErrorOnNotFound === true) {
                        vpGrid.logError({
                            functionName: "fillWithRowData",
                            message: "Cannot find input fields with selector : '" + inputFieldSelector + "'",
                            info: "Check that all input fields is tagged with the html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'"
                        });
                        return this;
                    }

                    var fieldsCount = jqInputFields.length;
                    for (var i = 0; i < fieldsCount; i++) {
                        var inputField = jqInputFields[i];
                        var jqInputField = $(inputField);
                        var colName = jqInputField.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                        var importColumnValue = jqInputField.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ImportColumnValue, true);

                        if (colName.isNullOrEmptyOrWhitespace()) {
                            vpGrid.logError({
                                functionName: "fillWithDataRow",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(inputField),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of a column"
                            });
                            continue;
                        }

                        if (JQGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "fillWithDataRow",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(inputField),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of an existing column."
                            });
                            continue;
                        }

                        if (importColumnValue === false) {
                            continue;
                        }

                        //var colModel = JQGrid.colModelOf(colName);
                        
                        var inputValue = dataRow[colName];
                        if (inputValue === undefined) {
                            inputValue = "";
                        }
                        jqInputField.val(inputValue);
                        //if input is a select, take only the displayed value
                        //TODO : create a keyValueFormatter to be able to handle the selected key directly
                        if (jqInputField.is('select')) {
                            jqInputField.setSelectedOptionWithText(inputValue);
                        }

                        if (jqInputField.is('span')) {
                            jqInputField.html("");
                            jqInputField.html(inputValue);
                        }

                    }//end for (var i = 0; i < fieldsCount; i++) 

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }
            }
        });


        $.fn.extend({
            getGridDataFromThisForm: function () {
                /// <signature>
                /// <summary>Get all the grid input fields that are present in this jQuery DOM element.
                /// </summary>
                /// <returns type="Object">returns a litteral object of all grid data found.</returns>
                /// </signature>
                try {
                    if (this === null) {
                        return null;
                    }

                    if (this === undefined) {
                        return null;
                    }

                    if (this.length === undefined) {
                        return null;
                    }

                    if (this.length === 0) {
                        return null;
                    }

                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = this.find(inputFieldSelector);

                    if (jqInputFields.notFound()) {
                        vpGrid.logError({
                            functionName: "getGridDataFromThisForm",
                            message: "Cannot find input fields with selector : '" + inputFieldSelector + "'",
                            info: "Check that all input fields are tagged with the html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'"
                        });
                        return null;
                    }

                    var fieldsCount = jqInputFields.length;
                    var dataRow = {};
                    for (var i = 0; i < fieldsCount; i++) {
                        var element = jqInputFields[i];
                        var jqElement = $(element);
                        var colName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                        if (colName.isNullOrEmptyOrWhitespace()) {
                            vpGrid.logError({
                                functionName: "getGridDataFromThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of a column"
                            });
                            continue;
                        }

                        if (JQGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "getGridDataFromThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of an existing column."
                            });
                            continue;
                        }

                        var inputValue = jqElement.val();


                        //if input is a select, take only the displayed value 
                        //      -> why?
                        //      because the selected value will be inserted in the grid. 
                        //      If we take the key then this key will be showed in the grid after row insertion, 
                        //      but the user does not want to see the key he wants to see what he has selected (CQFD)
                        //TODO : create a keyValueFormatter to be able to handle the selected key directly
                        if (jqElement.is('select')) {
                            var jqSelectedOption = jqElement.find('option:selected');
                            inputValue = jqSelectedOption.text();
                        }

                        //unformat the input value
                        var sanitizedValue = JQGrid.unformatThisValueWithCol(inputValue, colName);

                        //dataRow[colName] = inputValue;
                        dataRow[colName] = sanitizedValue;

                    }//end for (var i = 0; i < fieldsCount; i++) 

                    //TODO : Gather all hidden inputs that are NOT tagged with vpGrid.HtmlDataTag.ColumnName

                    return dataRow;

                } catch (e) {
                    vpGrid.logException(e);
                    return null;
                }

            }
        });



        $.fn.extend({
            insertNewRowFromThisForm: function (pos) {
                /// <signature>
                /// <summary>Insert a new row in the grid from this form element.</summary>
                /// <param name="pos" type="String">Position of insertion in the grid. Valid values are : 'last' and 'first'</param>
                /// <returns type="void"></returns>
                /// </signature>
                try {
                    if (this === null) {
                        return this;
                    }

                    if (this === undefined) {
                        return this;
                    }

                    if (this.length === undefined) {
                        return this;
                    }

                    if (this.length === 0) {
                        return this;
                    }

                    if (isNullOrUndefinedOrEmpty(pos)) {
                        pos = 'last';
                    }

                    var dataRow = this.getGridDataFromThisForm();

                    if (dataRow === null) {
                        vpGrid.logError({
                            functionName: "insertNewRowFromThisForm",
                            message: "Cannot find grid data on this form",
                            info: "Check that all input fields are tagged with the html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'"
                        });
                        return this;
                    }

                    vpGrid.insertNewRow(dataRow, pos);

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }
                
            }
        });


        $.fn.extend({
            updateRowFromThisForm: function (params) {
                /// <signature>
                /// <summary>Insert a new row in the grid from this form element.</summary>
                /// <param name="params" type="Object">Object literal to be sent to the server</param>
                /// <returns type="void"></returns>
                /// </signature>
                try {
                    if (this === null) {
                        return this;
                    }

                    if (this === undefined) {
                        return this;
                    }

                    if (this.length === undefined) {
                        return this;
                    }

                    if (this.length === 0) {
                        return this;
                    }

                    if (isNullOrUndefinedOrEmpty(params)) {
                        params = {};
                    }

                    var dataRow = this.getGridDataFromThisForm();

                    if (dataRow === null) {
                        vpGrid.logError({
                            functionName: "updateRowFromThisForm",
                            message: "Cannot find grid data on this form",
                            info: "Check that all input fields are tagged with the html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'"
                        });
                        return this;
                    }

                    vpGrid.updateRow(dataRow, params);
                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }

            }
        });


        $.fn.extend({
            parentModalDialogId: function () {
                /// <signature>
                /// <summary>Get the id of the enclosing modal dialog window.
                /// the parent modal dialog has the following signature:
                /// <div role="vpgrid-modal-dialog"
                ///         title="Add new Item"
                ///         class="vpgrid-hidden vpgrid-container vpgrid-modal-dialog"
                ///         data-vpgrid-dialog-id="vpGridAddNewItem" >
                ///
                /// </summary>
                /// <returns type="String">Returns the found value of the data attribute data-vpgrid-dialog-id</returns>
                /// </signature>
                try {
                    if (this.notFound()) {
                        return '';
                    }

                    var modalDialogSelector = 'div[role=vpgrid-modal-dialog]';
                    var jqModalDialog = this.closest(modalDialogSelector);

                    if (jqModalDialog.notFound()) {
                        // TODO : log
                        return '';
                    }

                    var dialogId = jqModalDialog.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, '');
                    return dialogId;


                } catch (e) {
                    vpGrid.logException(e);
                    return '';
                }
            }
        });

        $.fn.extend({
            openParentTab: function () {
                /// <signature>
                /// <summary>Set the focus on the parent jquery-ui Tab.
                /// </summary>
                /// <returns type="Void"></returns>
                /// </signature>
                try {
                    if (this.notFound()) {
                        return;
                    }

                    var parentTabPanelSelector = 'div[role=tabpanel]';
                    var jqParentTabPanel = this.closest(parentTabPanelSelector);

                    if (jqParentTabPanel.notFound()) {
                        //vpGrid.logError({
                        //    functionName: "openParentTab",
                        //    message: "Cannot find parent Tab with selector : '" + parentTabPanelSelector + "'",
                        //    info: "Check that jquery-ui Tab is properly setup as a parent of this element : \n" + outerHtml(this[0])
                        //});
                        return;
                    }

                    var tabId = jqParentTabPanel[0].id;
                    var jqTabs = jqParentTabPanel.closest('div.ui-tabs');
                    jqTabs.find('a[href=#' + tabId + ']').click();


                } catch (e) {
                    vpGrid.logException(e);

                }
            }
        });


        $.fn.extend({
            validateThisForm: function () {
                /// <signature>
                /// <summary>Validate all fields in the current form element.</summary>
                /// <returns type="Object">Returns a literal object that contains the result of the validation process.
                ///                         this object has the following structure : 
                ///                         {
                ///                             isValid: true | false,
                ///                             <colName> : {isValid:true|false, message:"any error message"}
                ///
                ///</returns>
                /// </signature>
                try {
                    if (this === null) {
                        return null;
                    }

                    if (this === undefined) {
                        return null;
                    }

                    if (this.length === undefined) {
                        return null;
                    }

                    if (this.length === 0) {
                        return null;
                    }

                    //if (this.isNot('form')) {
                    //    vpGrid.logError({
                    //        functionName: "validateNewRow",
                    //        message: "This method should be called on a form element.",
                    //        info: "This method has been called on element :\n" + outerHtml(this[0])
                    //    });
                    //    return null;
                    //}

                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = this.find(inputFieldSelector);

                    if (jqInputFields.notFound()) {
                        vpGrid.logError({
                            functionName: "validateThisForm",
                            message: "Cannot find input fields with selector : '" + inputFieldSelector + "'",
                            info: "Check that all input fields is tagged with the html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'"
                        });
                        return null;
                    }


                    var fieldsCount = jqInputFields.length;
                    var validationResult = {
                        isValid : true
                    };
                    for (var i = 0; i < fieldsCount; i++) {
                        var element = jqInputFields[i];
                        var jqElement = $(element);
                        var colName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                        if (colName.isNullOrEmptyOrWhitespace()) {
                            vpGrid.logError({
                                functionName: "validateThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of a column"
                            });
                            continue;
                        }

                        if (JQGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "validateThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of an existing column."
                            });
                            validationResult.isValid = false;
                            validationResult[colName] = {
                                isValid: false,
                                message: 'there is an internal configuration error on this field. Check error log.'
                            };
                            continue;
                        }

                        var inputValue = jqElement.val();
                        validationResult[colName] = {
                            isValid: true,
                            message: '',
                            value: inputValue
                        };

                        //unformat the input value
                        var sanitizedValue = JQGrid.unformatThisValueWithCol(inputValue, colName);

                        var jqGridTable = JQGrid.host();
                        var jqGridValidationResult = $.jgrid.checkValues.call(jqGridTable[0], sanitizedValue, colName);
                        if (isNullOrUndefinedOrEmpty(jqGridValidationResult)) {
                            //TODO : log
                            continue;
                        }

                        if (jqGridValidationResult[0] === false) {
                            validationResult.isValid = false;
                            validationResult[colName] = {
                                isValid: false,
                                message: jqGridValidationResult[1]
                            };
                            continue;
                        }

                    }//end for (var i = 0; i < fieldsCount; i++) 


                    if (validationResult.isValid === false) {
                        return validationResult;
                    }

                    //TODO : raise event to let listeners do a global custom validation on the form
                    var eventArgs = {
                        modalDialogId : this.parentModalDialogId(),
                        validationResult: validationResult,
                        isValid : true
                    };

                    //raise event
                    onFormValidating(this, eventArgs);

                    //take listener's validation results
                    validationResult = eventArgs.validationResult;
                    validationResult.isValid = eventArgs.isValid;

                    return validationResult;

                } catch (e) {
                    vpGrid.logException(e);
                    return null;
                }

            }
        });

        $.fn.extend({
            showValidationErrorsOnThisForm: function (validationResult) {
                /// <signature>
                /// <summary>Show all validation error messages on this form.</summary>
                /// <param name="validationResult" type="Object">Literal object that contains validation errors. Look at validateThisForm jQuery extension to see the details of that object.</param>
                /// <returns type="void"></returns>
                /// </signature>
                try {
                    if (this === null) {
                        return this;
                    }

                    if (this === undefined) {
                        return this;
                    }

                    if (this.length === undefined) {
                        return this;
                    }

                    if (this.length === 0) {
                        return this;
                    }

                    if (isNullOrUndefinedOrEmpty(validationResult)) {
                        //TODO : reset all validation error messages
                    }

                    //if (this.isNot('form')) {
                    //    vpGrid.logError({
                    //        functionName: "showValidationErrorsOnThisForm",
                    //        message: "This method should be called on a form element.",
                    //        info: "This method has been called on element :\n" + outerHtml(this[0])
                    //    });
                    //    return this;
                    //}

                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = this.find(inputFieldSelector);

                    if (jqInputFields.notFound()) {
                        vpGrid.logError({
                            functionName: "showValidationErrorsOnThisForm",
                            message: "Cannot find input fields with selector : '" + inputFieldSelector + "'",
                            info: "Check that all input fields is tagged with the html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'"
                        });
                        return this;
                    }

                    var fieldsCount = jqInputFields.length;
                    var dataRow = {};
                    for (var i = 0; i < fieldsCount; i++) {
                        var element = jqInputFields[i];
                        var jqElement = $(element);
                        var colName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                        if (colName.isNullOrEmptyOrWhitespace()) {
                            vpGrid.logError({
                                functionName: "showValidationErrorsOnThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of a column"
                            });
                            continue;
                        }

                        if (JQGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "showValidationErrorsOnThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of an existing column."
                            });
                            continue;
                        }

                        var jqInputDivContainer = jqElement.closest('div');
                        var jqErrorMessageDiv = jqInputDivContainer.find('div.ui-validation-message');

                        if (jqErrorMessageDiv.notFound()) {
                            jqErrorMessageDiv = $("<div></div>", {
                                'class' : 'ui-validation-message vpgrid-hidden'
                            });
                            jqErrorMessageDiv.insertAfter(jqElement);
                        }
      
                        var inputValidationResult = validationResult[colName];
                        if (isNullOrUndefinedOrEmpty(inputValidationResult)) {
                            jqErrorMessageDiv.html("");
                            jqErrorMessageDiv.addClass('vpgrid-hidden');

                            jqElement.removeClass('ui-state-error');

                            continue;
                        }

                        if (inputValidationResult.isValid) {
                            jqErrorMessageDiv.html("");
                            jqErrorMessageDiv.addClass('vpgrid-hidden');

                            jqElement.removeClass('ui-state-error');
                            //jqInputDivContainer.removeClass('height-auto');

                            continue;
                        }

                        jqErrorMessageDiv.html(inputValidationResult.message);
                        jqErrorMessageDiv.removeClass('vpgrid-hidden');
                        jqElement.addClass('ui-state-error');
                        jqInputDivContainer.addClass('height-auto');
                        
                    }//end for (var i = 0; i < fieldsCount; i++) 


                    //set focus on jquery-ui Tab where there is an error
                    var invalidInputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "].ui-state-error";
                    var jqInvalidInputFields = this.find(invalidInputFieldSelector);
                    if (jqInvalidInputFields.found()) {
                        jqInvalidInputFields.first().openParentTab();
                        //jqInvalidInputFields.first().focus();
                    }

                    
                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }

            }
        });

        $.fn.extend({
            resetValidationErrors: function () {
                /// <signature>
                /// <summary>Remove all validation error messages on this form.</summary>
                /// <returns type="void"></returns>
                /// </signature>
                try {
                    if (this === null) {
                        return this;
                    }

                    if (this === undefined) {
                        return this;
                    }

                    if (this.length === undefined) {
                        return this;
                    }

                    if (this.length === 0) {
                        return this;
                    }

                    //if (this.isNot('form')) {
                    //    vpGrid.logError({
                    //        functionName: "resetValidationErrors",
                    //        message: "This method should be called on a form element.",
                    //        info: "This method has been called on element :\n" + outerHtml(this[0])
                    //    });
                    //    return this;
                    //}

                    var validationSelector = 'div.ui-validation-message';
                    var jqValidations = this.find(validationSelector);

                    jqValidations.html("").addClass('vpgrid-hidden');

                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = this.find(inputFieldSelector);

                    jqInputFields.removeClass('ui-state-error');

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }

            }
        });

        $.fn.extend({
            setSelectedOptionWithText: function (inputText) {
                /// <signature>
                /// <summary>Set the selected option on a select element. The option is selected if its text matches input text.</summary>
                /// <param name="inputText" type="String">Option display text to search for on the selec element.</param>
                /// <returns type="void"></returns>
                /// </signature>
                try {
                    if (this === null) {
                        return this;
                    }

                    if (this === undefined) {
                        return this;
                    }

                    if (this.length === undefined) {
                        return this;
                    }

                    if (this.length === 0) {
                        return this;
                    }

                    if (! this.is('select')) {
                        vpGrid.logError({
                            message: "Dom element is not a SELECT : \n" + outerHtml(this[0]),
                            functionName: "setSelectedOptionWithText"
                            
                        });
                    }

                    var jqOptions = this.find('option');
                    if (jqOptions.notFound()) {
                        return this;
                    }

                    var optionsCount = jqOptions.length;
                    for (var i = 0; i < optionsCount; i++) {
                        var selectOption = jqOptions[i];
                        var jqSelectOption = $(selectOption);
                        var optionText = jqSelectOption.text();

                        if (optionText === inputText) {
                            jqSelectOption.attr('selected', 'true');
                            break;
                        }

                        try {
                            if (optionText.toLowerCase() === inputText.toLowerCase()) {
                                jqSelectOption.attr('selected', 'true');
                                break;
                            }
                            
                        } catch (e) {
                            vpGrid.logException(e);
                        }

                        //TODO : compare by using current culture
                       

                    } // end for (var i = 0; i < optionsCount; i++) {

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }

            }
        });



        $.fn.extend({
            autoValidateThisField: function () {
                /// <signature>
                /// <summary>Dynamically validate current field</summary>
                /// <returns type="void">
                /// </returns>
                /// </signature>
                try {
                    if (this.notFound()) {
                        return;
                    }

                    var jqElement = $(this);
                    // check if handlers have already been registered 
                    var handlerRegistered = jqElement.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ValidationHandlersRegistered, false);
                    if (handlerRegistered) {
                        return;
                    }

                    // flag that validation event handler has already been binded
                    jqElement.attr(vpGrid.HtmlDataTag.ValidationHandlersRegistered, "true");

                    //add css to render input fields as in modern web sites
                    if (jqElement.is('input') ||jqElement.is('select') || jqElement.is('textarea')) {
                        jqElement.addClass("vpgrid-input-field");
                    }
                    
                    var fieldName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                    if (fieldName === '') {
                        fieldName = jqElement.toStringOrDefaultFromAttribute("name", "");
                    }


                    jqElement.on('keyup keypress blur change', function () {
                        try {
                            var context = this;
                            var debounceKey = "autoValidateThisField";
                             
                            //make the debounceKey unique for each input (otherwise event is raised on the wrong input)
                            debounceKey = debounceKey + fieldName;

                            executeAsync(context, function () {
                                try {
                                    // keyword this represent the HTML DOM element on which the blur event is raised
                                    var element = this;
                                    var jqElement = $(this);
                                    var inputValue = jqElement.val();
                                    var validationResult = {
                                        isValid: true,
                                        message: '',
                                        value: inputValue
                                    };

                                    var colName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                                    if (colName.isNullOrEmptyOrWhitespace()) {
                                        vpGrid.logError({
                                            functionName: "autoValidateThisField",
                                            message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                            info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of a column"
                                        });
                                        return;
                                    }

                                    if (JQGrid.colDoesNotExist(colName)) {
                                        vpGrid.logError({
                                            functionName: "autoValidateThisField",
                                            message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                            info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of an existing column."
                                        });
                                        return;
                                    }

                                    //unformat the input value
                                    var sanitizedValue = JQGrid.unformatThisValueWithCol(inputValue,colName);

                                    var jqGridTable = JQGrid.host();
                                    var jqGridValidationResult = $.jgrid.checkValues.call(jqGridTable[0], sanitizedValue, colName);
                                    //TODO : modify checkvalue to make invalid a date like '21//2014'

                                    if (isNullOrUndefinedOrEmpty(jqGridValidationResult)) {
                                        //TODO : log
                                        return;
                                    }

                                    if (jqGridValidationResult[0] === false) {
                                        validationResult.isValid = false;
                                        validationResult.message = jqGridValidationResult[1];
                                    }

                                    jqElement.showValidationErrorOnThisField(validationResult);

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            }, 500, debounceKey); // end executeAsync(this[0], function () {


                        } catch (e) {
                            vpGrid.logException(e);
                        }
                    }); // end this.bind('blur', function () {


                } catch (e) {
                    vpGrid.logException(e);
                    return ;
                }

            }
        });

        $.fn.extend({
            autoValidateThisForm: function () {
                /// <signature>
                /// <summary>Auto validate each input fields on this form.</summary>
                /// <returns type="void"></returns>
                /// </signature>
                try {
                    if (this.notFound()) {
                        return this;
                    }

                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = this.find(inputFieldSelector);

                    if (jqInputFields.notFound()) {
                        vpGrid.logError({
                            functionName: "autoValidateThisForm",
                            message: "Cannot find input fields with selector : '" + inputFieldSelector + "'",
                            info: "Check that input fields are tagged with the html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'"
                        });
                        return this;
                    }

                    var fieldsCount = jqInputFields.length;
                    
                    for (var i = 0; i < fieldsCount; i++) {
                        var element = jqInputFields[i];
                        var jqElement = $(element);

                        if (jqElement.hasClass('vpgrid-hidden')) {
                            //do not auto validate fields that are hidden
                            // do not use jquery is(':visible') because parent Dialog container is always hidden
                            continue;
                        }

                        if (jqElement.css('display') === 'none') {
                            //do not auto validate fields that are hidden
                            continue;
                        }

                        var colName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                        if (colName.isNullOrEmptyOrWhitespace()) {
                            vpGrid.logError({
                                functionName: "autoValidateThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of a column"
                            });
                            continue;
                        }

                        if (JQGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "autoValidateThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of an existing column."
                            });
                            continue;
                        }

                        jqElement.autoValidateThisField();

                    }//end for (var i = 0; i < fieldsCount; i++) 


                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }

            }
        });

        $.fn.extend({
            showValidationErrorOnThisField: function (validationResult) {
                /// <signature>
                /// <summary>Show validation error message on this field.</summary>
                /// <param name="validationResult" type="Object">Literal object that contains validation error. This object has the following structure:
                ///             validationResult = {
                ///                 isValid: true|false,
                ///                 message: '', -> error message when isValid = false
                ///                 value: inputValue -> value entered by the user
                //}             ;
                /// </param>
                /// <returns type="void"></returns>
                /// </signature>
                try {
                    if (this.notFound()) {
                        return this;
                    }

                    if (isNullOrUndefinedOrEmpty(validationResult)) {
                        //TODO : reset all validation error messages
                        vpGrid.logError({
                            functionName: "showValidationErrorOnThisField",
                            message: "ValidationResult parameter is null or empty or  : '" + validationResult + "'",
                            info: "Check configuration and code on this element :\n" + outerHtml(this[0])
                        });
                        return this;

                    }

                    var jqElement = this;
                    var jqInputDivContainer = jqElement.closest('div');
                    var jqErrorMessageDiv = jqInputDivContainer.find('div.ui-validation-message');

                    if (jqErrorMessageDiv.notFound()) {
                        jqErrorMessageDiv = $("<div></div>", {
                            'class': 'ui-validation-message vpgrid-hidden'
                        });
                        jqErrorMessageDiv.insertAfter(jqElement);
                    }

                    if (validationResult.isValid) {
                        jqErrorMessageDiv.html("");
                        jqErrorMessageDiv.addClass('vpgrid-hidden');

                        jqElement.removeClass('ui-state-error');
                        //jqInputDivContainer.removeClass('height-auto');

                        return this;
                    }


                    jqErrorMessageDiv.html(validationResult.message);
                    jqErrorMessageDiv.removeClass('vpgrid-hidden');
                    jqElement.addClass('ui-state-error');
                    jqInputDivContainer.addClass('height-auto');

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }

            }
        });


        $.fn.extend({
            resetInputFields: function () {
                /// <signature>
                /// <summary>Reset Input controls to their original values.
                ///         Only controls tagged with the data-tag attribute : data-vpgrid-column-name
                ///         are reseted
                ///</summary>
                /// </signature>
                try {
                    var jqElement = $(this);
                    if (jqElement.notFound()) {
                        vpGrid.logError({
                            message: "selector not found : " + jqElement.selector,
                            functionName: "resetInputFields"
                        });
                        return;
                    }

                    //fill input element from selected item
                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = jqElement.find(inputFieldSelector);

                    var fieldsCount = jqInputFields.length;
                    for (var i = 0; i < fieldsCount; i++) {
                        var inputField = jqInputFields[i];
                        var jqInputField = $(inputField);

                        if (jqInputField.attr(vpGrid.HtmlDataTag.OriginalValue) === undefined) {
                            // first time this method is called
                            // so we must resgister the original value
                            var originalValue = jqInputField.val();
                            jqInputField.attr(vpGrid.HtmlDataTag.OriginalValue, originalValue);
                            continue;
                        }

                        var originalValue = jqInputField.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.OriginalValue, "");
                        jqInputField.val(originalValue);

                    }//end for (var i = 0; i < fieldsCount; i++) 

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }
            }
        });


        // end jQuery extensions

        //private extensions
        function isEmpty(input) {
            try {

                if (input === undefined) {
                    return true;
                }

                if (input === null) {
                    return true;
                }

                if (input.length === 0) {
                    return true;
                }

                //check for native types
                if (typeof input === "number") {
                    return false;
                }

                //check for native types
                if (typeof input === "boolean") {
                    return false;
                }

                if (typeof input === "function") {
                    return false;
                }

                // check for empty literal object
                var propertyCount = 0;
                for (var i in input) {
                    propertyCount += 1;
                }
                if (propertyCount === 0) {
                    return true;
                }

                return false;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        }

        function isNullOrUndefined(input) {
            try {
                if (input === undefined) {
                    return true;
                }

                if (input === null) {
                    return true;
                }

                return false;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        }

        function isNullOrUndefinedOrEmpty(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return true;
                }

                return isEmpty(input);

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        }

        function isNotNullOrUndefinedOrEmpty(input) {
            return isNullOrUndefinedOrEmpty(input) === false;
        }

        function isBoolean(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return false;
                }

                if (typeof input === "boolean") {
                    return true;
                }

                return false;
            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        }

        function isNotBoolean(input) {
            return isBoolean(input) === false;
        }

        function isString(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return false;
                }

                if (typeof input === "string") {
                    return true;
                }
                //hack from hdo
                if (typeof input.isString !== "function") {
                    return false;
                }

                if (input.isString()) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        function isNotString(input) {
            return isString(input) === false;
        };

        function isFunction(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return false;
                }

                if (typeof input === "function") {
                    return true;
                }

                return false;
            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        };

        function isNotFunction(input) {
            return isFunction(input) === false;
        };

        function isNumber(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return false;
                }
                if (isNaN(input)) {
                    return false;
                }
                if (typeof input === "number") {
                    return true;
                }

                if (isNotString(input)) {
                    return false;
                }

                // at this step we know that input is a string
                // try to convert to float
                var numberValue = input.toFloat();
                if (isNaN(numberValue)) {
                    return false;
                }

                return true;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        function isNotNumber(input) {
            return isNumber(input) === false;
        };

        function isInt(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return false;
                }
                if (isNaN(input)) {
                    return false;
                }

                if (typeof input !== "number") {
                    return false;
                }

                var remainder = input % 1;
                if (remainder === 0) {
                    return true;
                }

                return false;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        };

        function isNotInt(input) {
            return isInt(input) === false;
        };

        function isArray(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return false;
                }

                // TODO : jsHint suggests to refactor
                //if (typeof input === "array") {
                //    return true;
                //}

                if (input.push) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        function isNotArray(input) {
            return isArray(input) === false;
        };

        function outerHtml(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return "";
                }

                if (element.outerHTML) {
                    return element.outerHTML;
                }

                return "";

            } catch (e) {
                vpGrid.logException(e);
                return "";
            }
        };

        function extendOrMerge(obj1, obj2) {
            /// <signature>
            /// <summary>Extend obj1 with obj2 properties.</summary>
            /// <param name="obj1" type="Object">a litteral object to be extended</param>
            /// <param name="obj2" type="Object">feeder object literal</param>
            /// <returns type="Object">Returns obj1 augmented with properties coming from obj2. If obj1 and obj2 have identical propertiy, this property is converted to an array in obj1, and obj2 property value is pushed in this array.</returns>
            /// </signature>
            try {
                if (isNullOrUndefinedOrEmpty(obj2)) {
                    return obj1;
                }

                if (isNullOrUndefined(obj1)) {
                    var newObj = {};
                    $.extend(newObj, obj2);
                    return newObj;
                }

                if (isEmpty(obj1)) {
                    $.extend(obj1, obj2);
                    return obj1;
                }

                for (var i in obj2) {
                    var propertyName = i;
                    // check if this property exists in obj1
                    if (obj1[propertyName]) {
                        convertPropertyToArray(obj1, propertyName);
                        obj1[propertyName].push(obj2[propertyName]);
                        delete obj2[propertyName];
                    }
                }

                $.extend(obj1, obj2);
                return obj1;

            } catch (e) {
                vpGrid.logException(e);
                return obj1;
            }

        };

        function convertPropertyToArray(input, propertyName) {
            try {

                if (isNullOrUndefinedOrEmpty(input)) {
                    return;
                }

                if (isNotString(propertyName)) {
                    return;
                }

                if (isNullOrUndefined(input[propertyName])) {
                    return;
                }

                // now we are sure that the property named propertyName exists on input object
                var obj = input[propertyName];
                if (isArray(obj)) {
                    // the conversion is already done
                    return input;
                }

                input[propertyName] = [];
                input[propertyName].push(obj);

                return input;

            } catch (e) {
                vpGrid.logException(e);
                return;
            }
        };

        function tryFindFunctionByName(input) {
            try {
                if (isNullOrUndefinedOrEmpty(input)) {
                    return null;
                }

                if (isNotString(input)) {
                    return null;
                }

                // check if the function exist in the root object
                var foundFunction = window[input];
                if (isFunction(foundFunction)) {
                    return foundFunction;
                }

                // function is defined in a namespace
                var namespaces = input.split(".");
                if (isNullOrUndefinedOrEmpty(namespaces)) {
                    return null;
                }

                var functionName = namespaces[namespaces.length - 1];
                var parentObject = window;
                for (var i = 0; i < namespaces.length - 1; i++) {
                    var namespace = namespaces[i];
                    parentObject = parentObject[namespace];
                }

                foundFunction = parentObject[functionName];
                if (isFunction(foundFunction)) {
                    return foundFunction;
                }

                vpGrid.logError({
                    functionName: "tryFindFunctionByName",
                    message: "Cannot find function named : '" + input + "'"
                });
                return null;

            } catch (e) {
                vpGrid.logException(e);
                return null;
            }
        };

        var asyncKeys = {};
        function executeAsync(context, f, delay, asyncKey) {
            try {
                if (isNullOrUndefined(context)) {
                    context = this;
                }

                if (isNotFunction(f)) {
                    vpGrid.logError({
                        functionName: "executeAsync",
                        message: "Input handler is not a function : '" + f + "'"
                    });
                    return;
                }

                var defaultDelay = 0;
                if (isNumber(delay)) {
                    defaultDelay = delay;
                }



                if (isNullOrUndefinedOrEmpty(asyncKey)) {
                    //setTimeout(f, defaultDelay);

                    setTimeout(function () {
                        f.call(context);
                    }, defaultDelay);

                    return;
                }

                //debounce
                if (asyncKeys[asyncKey]) {
                    clearTimeout(asyncKeys[asyncKey]);
                }
                asyncKeys[asyncKey] = setTimeout(function () {
                    f.call(context);
                }, defaultDelay);


            } catch (e) {
                vpGrid.logException(e);
                setTimeout(f, 0);
            }
        };

        vpGrid.executeAsyncLoopOnArray = function (input, f, context, onEnd, cancel, onCanceled) {
            /// <signature>
            /// <summary>Excute callback f on each item of input array. 
            ///     At each iteration the thread is released and the UI thread can still process user actions</summary>
            ///     The callback must have the following signature function(i,item){} where i is the loop counter and item is input[i]
            /// <param name="input" type="Array">Array of object</param>
            /// <param name="f" type="Function">the callback that is called at each iteration</param>
            /// <param name="context" type="Object">The object that will be accessible within the callback with the this keyword.</param>
            /// <param name="onEnd" type="Function">The callback that will be called when all iterations are done.</param>
            /// <param name="cancel" type="Function">The callback that will be called at each iteration to check if the loop must be canceled due to external business conditions.</param>
            /// <param name="onCanceled" type="Function">The callback that will be called if the loop has been canceled</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                if (isNotArray(input)) {
                    vpGrid.logError({
                        functionName: "vpGrid.executeAsyncLoopOnArray",
                        message: "input parameter is not an array but is: '" + input + "'"
                    });
                }

                var itemCount = input.length;
                if (itemCount === 0) {
                    //nothing to do
                    return;
                }

                if (isNullOrUndefined(context)) {
                    context = this;
                }

                var i = -1;
                var canceled = false;

                var cancelCallbackMustBeCalled = false;
                if (isFunction(cancel)) {
                    cancelCallbackMustBeCalled = true;
                }

                function processNext() {
                    try {
                        var item = input.shift();
                        i += 1;
                        f.call(context, i, item);

                        //check if the loop must be canceled
                        if (cancelCallbackMustBeCalled) {
                            canceled = cancel.call(context, i, item);
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                    finally {
                        // check for end of loop
                        if (input.length === 0 && onEnd === undefined) {
                            return;
                        }

                        if (input.length === 0 && isFunction(onEnd)) {
                            onEnd.call(context);
                            return;
                        }

                        if (canceled === true && isFunction(onCanceled)) {
                            onCanceled.call(context);
                            return;
                        }

                        if (canceled === true) {
                            return;
                        }

                        //release thread to let the UI be responsive
                        setTimeout(processNext, 0);
                    }
                };

                processNext();

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function isCustomPropertyOf(input, property) {
            /// <signature>
            /// <summary>Check if a property is a custom property of input literal object. You should use this method only with literal objects.</summary>
            /// <param name="input" type="Object">Literal object on which the property is searched</param>
            /// <param name="property" type="Object">The property to search on input literal object.</param>
            /// <returns type="Boolean">Returns true if the property is a custom property inside input literal object.</returns>
            /// </signature>
            try {

                if (input === null) {
                    return false;
                }

                if (input === undefined) {
                    return false;
                }

                if (!input.hasOwnProperty) {
                    return false;
                }

                if (input.hasOwnProperty(property)) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        function isNotCustomPropertyOf(input, property) {
            return isCustomPropertyOf(input, property) === false;
        };

        function areEquals(input1, input2) {
            /// <signature>
            /// <summary>Check if a literal object input1  is equal to input2 literal object. You should compare only literal objects. </summary>
            /// <param name="input1" type="Object">Literal object</param>
            /// <param name="input2" type="Object">Literal object to be compared with input1</param>
            /// <returns type="Boolean">Returns true if input1 has same properties and values as input2 literal object.</returns>
            /// </signature>
            try {
                if (input1 === null) {
                    return false;
                }

                if (input1 === undefined) {
                    return false;
                }

                if (input2 === null) {
                    return false;
                }

                if (input2 === undefined) {
                    return false;
                }

                for (var p in input1) {
                    if (isNotCustomPropertyOf(input2, p)) {
                        return false;
                    }
                    if (input1[p] !== input2[p]) {
                        return false;
                    }
                }

                return true;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        function isInRange(input, minValue, maxValue) {
            /// <signature>
            /// <summary>Check if input value is between minValue and maxValue</summary>
            /// <param name="input" type="Number">Input value</param>
            /// <param name="minValue" type="Number">Minimum value of the interval</param>
            /// <param name="maxValue" type="Number">Max value of the interval</param>
            /// <returns type="Boolean">Returns true if input is in the interval.</returns>
            /// </signature>
            try {

                if (minValue === null && maxValue === null) {
                    return true;
                }

                if (isNotNumber(input)) {
                    return false;
                }

                if (isString(input)) {
                    input = input.toFloat();
                }

                if (input.isGreaterThan(maxValue)) {
                    return false;
                }

                if (input.isLowerThan(minValue)) {
                    return false;
                }

                return true;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        function isOutOfRange(input, minValue, maxValue) {
            /// <signature>
            /// <summary>Check if input value is not in the interval [minValue,maxValue]</summary>
            /// <param name="input" type="Number">Input value</param>
            /// <param name="minValue" type="Number">Minimum value of the interval</param>
            /// <param name="maxValue" type="Number">Max value of the interval</param>
            /// <returns type="Boolean">Returns true if input is not in the interval.</returns>
            /// </signature>
            return isInRange(input, minValue, maxValue) === false;
        };

        

        //end private extensions

        // jQuery-UI extensions
        function bindWidgetOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                // take the name of the widget from the data tag
                var widgetType = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIWidget, "");

                //deserialize the configuration options object from the data tag
                var dataTag = vpGrid.HtmlDataTag.UIWidgetOptions.removePrefix("data-");
                var widgetOptions = jqElement.data(dataTag);

                if (widgetType === "datepicker") {
                    // bind datepicker widget
                    //merge widget Options with vpGrid datepicker Options
                    var mergedOptions = $.extend({}, vpGrid.options.datepickerOptions, widgetOptions);
                    
                    jqElement.datepicker(mergedOptions);
                    return;
                } // end if

                if (widgetType === "button") {
                    // bind button widget
                    jqElement.button(widgetOptions);
                    return;
                } // end if

                if (widgetType === "dialog") {
                    // bind dialog widget
                    // bind internal event handler onDialogClosed
                    //TODO : check if an handler is already bound
                    var source = element;
                    widgetOptions.close = function (event, ui) {
                        try {
                            var eventArgs = {};
                            // raise event so that listeners can do extra process
                            onModalDialogClosed(source, eventArgs);

                        } catch (e) {
                            vpGrid.logException(e);
                        }
                    };

                    jqElement.dialog(widgetOptions);
                    return;
                } // end if

                if (widgetType === "autocomplete") {
                    //bind autocomplete widget
                    bindAutoCompleteWidgetOnElement(element);
                    return;
                } // end if

                if (widgetType === "accordion") {
                    //bind accordion widget
                    jqElement.accordion(widgetOptions);
                    return;
                } // end if

                if (widgetType === "tabs") {
                    //bind tabs widget
                    jqElement.tabs(widgetOptions);
                    return;
                } // end if

                if (widgetType === "fileupload") {
                    //bind File Upload widget (http://blueimp.github.io/jQuery-File-Upload/)
                    bindFileUploadWidgetOnElement(element);
                    return;
                } // end if


                vpGrid.logError({
                    functionName: "bindWidgetOnElement",
                    message: "widget binding is not implemented for widget : '" + widgetType + "'  in vpGrid.",
                    info: "This widget is not binded on element : \n" + outerHtml(element)
                });

            } catch (e) {
                vpGrid.logException(e);
            }
        };




        function bindFileUploadWidgetOnElement(element) {
            /// <signature>
            /// <summary>Bind the Jquery plgin File Upload from http://blueimp.github.io/jQuery-File-Upload/ </summary>
            /// <param name="element" type="Object">DOM object on which to bind the jquery plugin</param>
            /// <returns type="Void"></returns>
            /// </signature>
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                //deserialize the configuration options object from the data tag
                var dataTag = vpGrid.HtmlDataTag.UIWidgetOptions.removePrefix("data-");
                var widgetOptions = jqElement.data(dataTag);

                jqElement.fileupload(widgetOptions);

                //bind events
                jqElement.bind('fileuploadsubmit', function (e, data) {
                    try {
                        var formData = data.formData || {};
                        var source = e.target;

                        var eventArgs = {
                            data : data,
                            formData: formData,
                            cancel : false
                        };

                        //raise event to enable listeners inspect/modify the formData or cancel the ajax submit call
                        onFileuploading(source, eventArgs);

                        if (isNotNullOrUndefinedOrEmpty(eventArgs.formData)) {
                            data.formData = eventArgs.formData;
                        }

                        if (eventArgs.cancel === true) {
                            return false;
                        }

                        return true;

                    } catch (e) {
                        vpGrid.logException(e);
                        // enable submit even if an error has occured
                        return true;
                    }

                });
                

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindAutoCompleteWidgetOnElement(element) {
            try {

                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                var widgetDataSource = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSource, "")
                var widgetDataSourceType = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSourceType, vpGrid.HtmlDataTag.DefaultValue.DataSourceType);

                if (widgetDataSource.isNullOrEmptyOrWhitespace()) {
                    //TODO : log
                    vpGrid.logError({
                        message: "data attribute : " + vpGrid.HtmlDataTag.DataSource + " is not defined on element \n: " + outerHtml(element)
                    });
                    return;
                }

                if (widgetDataSourceType === "web") {
                    bindAutoCompleteWidgetFromWebOnElement(element, widgetDataSource);
                    return;
                }

                //TODO : log
                vpGrid.logError({
                    functionName: "bindAutoCompleteWidgetOnElement",
                    message: "data attribute : " + vpGrid.HtmlDataTag.DataSourceType + " on element \n: " + outerHtml(element) + "\n has a value that is not implemented in vpGrid."
                });

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindAutoCompleteWidgetFromWebOnElement(element, dataSourceUrl) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                var ajaxOptions = {
                    cache: false,
                    type: "GET",
                    url: dataSourceUrl,
                    dataType: "json",
                    element: element,
                    success: function (response) {
                        bindAutoCompleteWidgetFromWebResponseOnElement(response, element);
                    }

                }

                $.extend(ajaxOptions, vpGridAjaxOptions);

                //TODO : raise event to enable listerners inspect and/or modify ajaxOptions

                $.ajax(ajaxOptions);


            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindAutoCompleteWidgetFromWebResponseOnElement(response, element) {
            try {

                //TODO : raise event to enable listerners inspect and/or modify response
                if (isNullOrUndefinedOrEmpty(response)) {
                    //TODO : log
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                if (response.done === undefined) {
                    //TODO : log
                    return;
                }

                if (response.done === false) {
                    var details = "Ajax Request error on fetching data for autocomplete";
                    logServerError(response, details, element);
                    return;
                }

                var data = response.data;
                bindAutoCompleteWidgetWithDataOnElement(element, data);
                bindChangeEventToAutoCompleteSelectOnElement(element);

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindAutoCompleteWidgetWithDataOnElement(element, data) {
            try {

                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                //deserialize the configuration options object from the data tag
                var dataTag = vpGrid.HtmlDataTag.UIWidgetOptions.removePrefix("data-");
                var widgetOptions = jqElement.data(dataTag);
                if (isNullOrUndefined(widgetOptions)) {
                    widgetOptions = {};
                }

                widgetOptions.source = data;

                var numberOfItems = 0;
                if (isArray(data)) {
                    numberOfItems = data.length;
                }
                var thresholdValue = 1000;

                // set default minLength value if not already setup
                if (isNullOrUndefinedOrEmpty(widgetOptions.minLength)) {
                    widgetOptions.minLength = 0;
                }

                //auto adapt minLength and delay according to the size of the data source array
                if ((numberOfItems > thresholdValue) && (widgetOptions.minLength === 0) ) {
                    widgetOptions.minLength = 1;
                    widgetOptions.delay = 600;
                }

                if ((numberOfItems > 2*thresholdValue) && (widgetOptions.minLength <= 1)) {
                    widgetOptions.minLength = 2;
                    widgetOptions.delay = 900;
                }
                
                if ((numberOfItems > 3 * thresholdValue) && (widgetOptions.minLength <= 2)) {
                    widgetOptions.minLength = 3;
                    widgetOptions.delay = 1200;
                }

                jqElement.autocomplete(widgetOptions);
                jqElement.bind('focus', function () {
                    try {
                        var jqCurrent = $(this);
                        executeAsync(this, function () {
                            try {
                                var currentValue = jqCurrent.val();
                                if (isNullOrUndefinedOrEmpty(currentValue)) {
                                    currentValue = "";
                                }

                                if (numberOfItems > thresholdValue) {
                                    // too many items in the autocomplete source array
                                    // do nothing to prevent the UI from being too busy
                                    return;
                                }

                                jqCurrent.autocomplete("search", currentValue);

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                });

                jqElement.bind('click', function () {
                    try {
                        var jqCurrent = $(this);
                        executeAsync(this, function () {
                            try {
                                if (numberOfItems > thresholdValue) {
                                    // too many items in the autocomplete source array
                                    // do nothing to prevent the UI from being too busy
                                    return;
                                }
                                jqCurrent.autocomplete("search", "");

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                });


            } catch (e) {
                vpGrid.logException(e);
            }
        };


        function bindChangeEventToAutoCompleteSelectOnElement(element) {
            try {

                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                jqElement.on('autocompleteselect', function (event, ui) {
                    try {
                        var context = this;
                        executeAsync(context, function () {
                            try {
                                $(this).trigger('change');

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                });


            } catch (e) {
                vpGrid.logException(e);
            }
        };


        function destroyWidgetOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                if (jqElement.datepicker) {
                    //unbind the close event
                    jqElement.datepicker("option", "onClose", function () { });
                    jqElement.datepicker('hide');
                    jqElement.datepicker("destroy");
                    return;
                }

                if (jqElement.autocomplete) {
                    jqElement.autocomplete("close");
                    jqElement.autocomplete("destroy");
                    return;
                }

                vpGrid.logError({
                    functionName: "destroyWidgetOnElement",
                    message: "Widget destroy is not implemented on element : " + outerHtml(element)
                });

                //TODO : implement destroy of other possible widgets

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function hideWidgetOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                if (jqElement.datepicker) {
                    jqElement.datepicker('hide');
                    return;
                }

                if (jqElement.autocomplete) {
                    jqElement.autocomplete("close");
                    return;
                }

                vpGrid.logError({
                    message: "Widget hide is not implemented on element : \n" + outerHtml(element)
                });

                //TODO : implement hide of other possible widgets

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        // end jQuery-UI extensions


        //UI extensions
        function applyDisabledStateOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                //raise event to let listeners enable/disable the DOM element
                var eventArgs = {
                    uiId: jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIIdentifier, ""),
                    cancel: false
                };
                onUIElementDisabling(element, eventArgs);

                if (eventArgs.cancel === true) {
                    jqElement.removeAttr('disabled').removeClass("ui-state-disabled");
                    return;
                }

                jqElement.attr('disabled', true).addClass("ui-state-disabled");


            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function applyActiveHeaderOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                jqElement.mouseenter(
                   function () {
                       $(this).find('[role=vpgrid-passive-header]').addClass('vpgrid-hidden');
                       $(this).find('[role=vpgrid-active-header]').removeClass('vpgrid-hidden');
                       $(this).saveOriginalClassAttributeContent();
                       $(this).addClass($(this).attr(vpGrid.HtmlDataTag.CssToAdd));
                       //bind event handlers
                       bindHandlersOnElement(this);
                   }
                   );

                jqElement.mouseleave(
                    function () {
                        $(this).find('[role=vpgrid-passive-header]').removeClass('vpgrid-hidden');
                        $(this).find('[role=vpgrid-active-header]').addClass('vpgrid-hidden');
                        $(this).restoreOriginalClassAttributeContent();


                    }
                    );

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindDataSourceOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                if (jqElement.is("select")) {
                    //bind data source on select
                    bindDataSourceOnSelectElement(element);
                    return;
                } // end if

                if (jqElement.is("input")) {
                    //bind data source on select
                    bindDataSourceOnInputElement(element);
                    return;
                } // end if

                //TODO : log
                vpGrid.logError({
                    functionName: "bindDataSourceOnElement",
                    message: "Data Source Binding is not implemented by vpGrid on this element : \n" + outerHtml(element) 
                });

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindDataSourceOnInputElement(element) {
            try {

                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                var dataSource = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSource, "")
                var dataSourceType = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSourceType, vpGrid.HtmlDataTag.DefaultValue.DataSourceType);

                if (dataSource.isNullOrEmptyOrWhitespace()) {
                    //TODO : log
                    vpGrid.logError({
                        functionName: "bindDataSourceOnInputElement",
                        message: "data attribute : " + vpGrid.HtmlDataTag.DataSource + " is not defined on element : \n" + outerHtml(element)
                    });
                    return;
                }

                if (dataSourceType === "queryString") {
                    var queryStringData = vpGrid.getQueryStringData();
                    var key = dataSource;
                    var value = queryStringData[key];
                    if (value === undefined) {
                        vpGrid.logError({
                            functionName: "bindDataSourceOnInputElement",
                            message: "The value : '" + dataSource + "' of the data attribute : " + vpGrid.HtmlDataTag.DataSource + " does not match a key in the query string of this url : " + document.location.search,
                            info: "Check this HTML element : \n" + +outerHtml(element)
                        });
                        return;
                    }
                    jqElement.val(value);
                    return;
                }

                //TODO : log
                vpGrid.logError({
                    functionName: "bindDataSourceOnInputElement",
                    message: "data attribute : " + vpGrid.HtmlDataTag.DataSourceType + " on element : \n" + outerHtml(element) + "\n has a value that is not implemented in vpGrid."
                });

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindDataSourceOnSelectElement(element) {
            try {

                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                var selectDataSource = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSource, "")
                var selectDataSourceType = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSourceType, vpGrid.HtmlDataTag.DefaultValue.DataSourceType);

                if (selectDataSource.isNullOrEmptyOrWhitespace()) {
                    //TODO : log
                    vpGrid.logError({
                        message: "data attribute : " + vpGrid.HtmlDataTag.DataSource + " is not defined on element : \n" + outerHtml(element)
                    });
                    return;
                }

                if (selectDataSourceType === "web") {
                    bindDataSourceFromWebOnSelectElement(element, selectDataSource);
                    return;
                }

                //TODO : log
                vpGrid.logError({
                    message: "data attribute : " + vpGrid.HtmlDataTag.DataSourceType + " on element : \n" + outerHtml(element) + "\n has a value that is not implemented in vpGrid."
                });



            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindDataSourceFromWebOnSelectElement(element, dataSourceUrl) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                //signal that a data binding operation is in process
                jqElement.attr(vpGrid.HtmlDataTag.DataSourceIsBinding, "true");

                var ajaxOptions = {
                    cache: false,
                    type: "GET",
                    url: dataSourceUrl,
                    dataType: "json",
                    element: element,
                    success: function (response) {
                        bindDataSourceFromWebResponseOnSelectElement(response, element);
                    },
                    complete: function (xhr, textStatus) {
                                try {
                                    // flag that data binding is finished
                                    var jqElement = $(element);
                                    jqElement.removeAttr(vpGrid.HtmlDataTag.DataSourceIsBinding);

                                    // bind handlers on the element if needed
                                    var handlers = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.Handlers, null)
                                    if (handlers !== null) {
                                        bindHandlersOnElement(element);
                                    }
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            }
                
                    };

                //Propagate all parameters from the Query String 
                var dataFromQueryString = vpGrid.getQueryStringData();
                if (isNotNullOrUndefinedOrEmpty(dataFromQueryString)) {
                    ajaxOptions.data = dataFromQueryString;
                }

                $.extend(ajaxOptions, vpGridAjaxOptions);

                //TODO : raise event to enable listerners inspect and/or modify ajaxOptions

                $.ajax(ajaxOptions);


            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindDataSourceFromWebResponseOnSelectElement(response, element) {
            try {

                //TODO : raise event to enable listerners inspect and/or modify response
                if (isNullOrUndefinedOrEmpty(response)) {
                    //TODO : log
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                if (response.done === undefined) {
                    //TODO : log
                    return;
                }

                if (response.done === false) {
                    var details = "Ajax Request error on fetching data for select element";
                    logServerError(response, details, element);
                    return;
                }

                var data = response.data;
                bindSelectWithDataOnElement(element, data);


            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindSelectWithDataOnElement(element, data) {
            try {

                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                //TODO : check that data param is an array
                //TODO ; check that items in the array are of the form { key:xx, value:yy [,selected: true]}

                //keep track of the currently selected item
                var jqSelectedOptionBefore = jqElement.find('option:selected');
                var selectedValueBefore = jqSelectedOptionBefore.val();

                //empty the select element
                jqElement.find('option').remove();

                var length = data.length;

                for (var i = 0; i < length; i++) {
                    var item = data[i];

                    var optionValue = item.key;
                    var optionText = item.value;
                    var isSelected = false;
                    if (item.selected === true) {
                        isSelected = true;
                    }

                    var optionElement = $("<option></option>").attr("value", optionValue).text(optionText);
                    if (isSelected) {
                        optionElement.attr("selected", "true");
                    }
                    jqElement.append(optionElement);

                }

                //Check if the selected item has changed
                //keep track of the currently selected item
                var jqSelectedOptionAfter = jqElement.find('option:selected');
                var selectedValueAfter = jqSelectedOptionAfter.val();

                if (selectedValueBefore !== selectedValueAfter) {
                    //raise the Change event
                    jqElement.change();
                }

                


            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function fillContentPlaceholderOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                var dataSource = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSource, "")
                var dataSourceType = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSourceType, vpGrid.HtmlDataTag.DefaultValue.DataSourceType);

                if (dataSource.isNullOrEmptyOrWhitespace()) {
                    //TODO : log
                    vpGrid.logError({
                        message: "data attribute : " + vpGrid.HtmlDataTag.DataSource + " is not defined on element : \n" + outerHtml(element)
                    });
                    return;
                }

                if (dataSourceType === "handler") {
                    fillContentPlaceholderFromHandlerOnElement(element, dataSource);
                    return;
                }

                //TODO : log
                vpGrid.logError({
                    message: "data attribute : " + vpGrid.HtmlDataTag.DataSourceType + " on element : \n" + outerHtml(element) + "\n has a value that is not implemented in vpGrid."
                });
            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function fillContentPlaceholderFromHandlerOnElement(element, handlerName) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                var handler = tryFindFunctionByName(handlerName)

                if (isNotFunction(handler)) {
                    var domHTML = outerHtml(element);
                    vpGrid.logError({
                        functionName: "fillContentPlaceholderFromHandlerOnElement",
                        message: "Cannot find handler named : '" + handlerName + "' defined on element: \n" + domHTML
                    });
                    return;
                }

                // call handler to get html content
                var newContent = handler();
                if (isNullOrUndefinedOrEmpty(newContent)) {
                    newContent = "";
                }

                jqElement.html(newContent);

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        // end UI extensions

        //UI event handlers auto binding
        function bindHandlersOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                // check if handlers have already been registered 
                var handlersRegistered = jqElement.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.HandlersRegistered, false);
                if (handlersRegistered) {
                    return;
                }

                //check if there is a data binding operation currently running on the element
                var dataSourceIsBinding = jqElement.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSourceIsBinding, false);
                if (dataSourceIsBinding) {
                    return;
                }

                //deserialize the configuration options object from the data tag
                var dataTag = vpGrid.HtmlDataTag.Handlers.removePrefix("data-");
                var handlers = jqElement.data(dataTag);


                //handlers is a literal object that is like :
                // {"click" : { "handler" : "MyCompany.MyHandler", "async" : true, "asyncKey" : "myHandlerKey"}}

                if (isNullOrUndefinedOrEmpty(handlers)) {
                    //TODO : log
                    return;
                }

                for (var i in handlers) {
                    var eventName = i;
                    var handlerOptions = handlers[i];
                    bindHandlerOnElement(element, eventName, handlerOptions);
                }

                // flag that events have been binded
                jqElement.attr(vpGrid.HtmlDataTag.HandlersRegistered, "true");


            } catch (e) {
                vpGrid.logException(e);
            }
            finally {

            }
        };

        function bindHandlerOnElement(element, eventName, handlerOptions) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                if (isNullOrUndefinedOrEmpty(eventName)) {
                    //TODO : log
                    return;
                }

                if (isNotString(eventName)) {
                    //TODO : log

                    return;
                }

                if (isNullOrUndefinedOrEmpty(handlerOptions)) {
                    //TODO : log
                    return;
                }

                var handlerName = handlerOptions.handler;
                var eventArgs = handlerOptions.params;
                var handler = tryFindFunctionByName(handlerName)

                if (isNotFunction(handler)) {
                    var domHTML = outerHtml(element);
                    vpGrid.logError({
                        message: "Cannot find handler named : '" + handlerName + "' for " + eventName + " event defined on element: \n" + domHTML
                    });
                    return;
                }

                if (isNullOrUndefined(handlerOptions.async)) {
                    handlerOptions.async = false;
                }

                if (eventName === "click" && handlerOptions.async === false) {
                    jqElement.click(function (event) {
                        try {
                            handler.call(this, event, eventArgs);
                        } catch (e) {
                            vpGrid.logException(e);
                        }
                    });
                    return;
                }

                if (eventName === "change" && handlerOptions.async === false) {
                    jqElement.change(function (event) {
                        try {
                            handler.call(this, event, eventArgs);
                        } catch (e) {
                            vpGrid.logException(e);
                        }
                    });

                    return;
                }

                if (eventName === "click" && handlerOptions.async === true) {
                    jqElement.click(function (event) {
                        //TODO : get asyncKey from data attribute
                        //TODO : get prevent default behavior from data attribute
                        if (event && event.preventDefault) {
                            event.preventDefault();
                        }

                        executeAsync(this, function () {
                            //propagate the context up to the event handler
                            try {
                                handler.call(this, event, eventArgs);
                            } catch (e) {
                                vpGrid.logException(e);
                            }
                            
                        });
                    });


                    return;
                }

                if (eventName === "change" && handlerOptions.async === true) {
                    jqElement.change(function (event) {
                        //TODO : get asyncKey from data attribute
                        //TODO : get prevent default behavior from data attribute

                        if (event && event.preventDefault) {
                            event.preventDefault();
                        }

                        executeAsync(this, function () {
                            //propagate the context up to the event handler
                            try {
                                handler.call(this, event, eventArgs);
                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });
                    });


                    return;
                }

                //TODO : log error event handler not implemented
                vpGrid.logError({
                    functionName: "bindHandlerOnElement",
                    message: "Event Handler binding is not implemented for event : '" + eventName + "'  in vpGrid.",
                    info: "This Event Handler is not binded on element : \n" + outerHtml(element)
                });

            } catch (e) {
                vpGrid.logException(e);
            }
            finally {

            }
        };
        //end UI event handlers auto binding


        


        //Private Events Enumeration
        var PrivateEvent = {};
        PrivateEvent.onBehaviorsRegistering = "private.onBehaviorsRegistering";

        //EventHandlers layer
        var EventHandlers = (function () {
            var eventHandlers = {};
            try {
                var listeners = {};
                //private methods on EventHandlers layer
                function eventHasListeners(eventName) {
                    try {
                        if (isNotString(eventName)) {
                            return false;
                        }

                        if (eventName.isNullOrEmptyOrWhitespace()) {
                            return false;
                        }

                        if (isNullOrUndefinedOrEmpty(listeners)) {
                            return false;
                        }

                        var eventNameListeners = listeners[eventName];

                        if (isNullOrUndefinedOrEmpty(eventNameListeners)) {
                            return false;
                        }

                        return true;

                    } catch (e) {
                        //TODO : log
                        vpGrid.logException(e);
                        return false;
                    }
                }

                function eventHasNoListener(eventName) {
                    return eventHasListeners(eventName) === false;
                }

                function eventHandlerIsRegistered(eventName, handler) {
                    try {
                        if (eventHasNoListener(eventName)) {
                            return false;
                        }

                        if (isNullOrUndefined(handler)) {
                            return false;
                        }

                        if (isNotFunction(handler)) {
                            return false;
                        }

                        // get all listeners for this event
                        var eventListeners = listeners[eventName];
                        var listernersCount = eventListeners.length;

                        for (var i = 0; i < listernersCount; i++) {
                            if (eventListeners[i] === handler) {
                                return true;
                            }
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                //public methods on this layer
                eventHandlers.registerEventHandler = function (eventName, handler) {
                    /// <signature>
                    /// <summary>Register your event handler to one of the vpGrid events</summary>
                    /// <param name="eventName" type="String">Name of the event you want to listen to. Possible names are defined in the the vpGrid enumeration vpGrid.Event</param>
                    /// <param name="handler" type="Function">Function that will be called when raising the event. This function must have the signature function(source, eventArgs){}, where source is the object that is at the origin of the event, and eventArgs is a placeholder object for informations needed by the listener.</param>
                    /// </signature>
                    try {
                        if (isNotFunction(handler)) {
                            vpGrid.logError({
                                functionName: "eventHandlers.registerEventHandler",
                                message: "The event handler is not a function.",
                                info: "Check the name of your event handler for event : '" + eventName  + "'."
                            });
                            return;
                        }

                        // check if event handler has already been registered
                        if (eventHandlerIsRegistered(eventName, handler)) {
                            return;
                        }
                        var eventListeners = listeners[eventName];
                        if (isNullOrUndefinedOrEmpty(eventListeners)) {
                            listeners[eventName] = [];
                        }

                        //TODO : check if eventName is a vpGrid event
                        listeners[eventName].push(handler);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                eventHandlers.raiseEvent = function (eventName, eventSource, eventArgs) {
                    try {
                        if (eventHasNoListener(eventName)) {
                            return;
                        }

                        var eventListeners = listeners[eventName];
                        var listernersCount = eventListeners.length;

                        for (var i = 0; i < listernersCount; i++) {
                            handler = eventListeners[i];
                            try {
                                // execute handler
                                handler(eventSource, eventArgs);

                                //TODO : check if cancel has been setup in eventArgs
                            } catch (e) {
                                //TODO : log
                                vpGrid.logException(e);
                            }
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }


            } catch (e) {
                //error in  EventHandlers layer
                vpGrid.logException(e);
            }
            finally {
                return eventHandlers;
            }

        })();
        //end EventHandlers layer
        // public interface on Event Handlers
        vpGrid.registerEventHandler = function (eventName, handler) {
            /// <signature>
            /// <summary>Register your event handler to one of the vpGrid events</summary>
            /// <param name="eventName" type="String">Name of the event you want to listen to. Possible names are defined in the the vpGrid enumeration vpGrid.Event</param>
            /// <param name="handler" type="Function">Function that will be called when raising the event. This function must have the signature function(source, eventArgs){}, where source is the object that is at the origin of the event, and eventArgs is a placeholder object for informations needed by the listener.</param>
            /// </signature>
            try {
                EventHandlers.registerEventHandler(eventName, handler);
            } catch (e) {
                vpGrid.logException(e);
            }

        };

        

        // end public interface on Event Handlers



        //Behaviors layer
        var Behaviors = (function () {
            var behaviors = {};
            try {
                // Sequence Enumeration
                behaviors.Sequence = {};
                behaviors.Sequence.SequenceInit = "SequenceInit";
                behaviors.Sequence.GridPreInit = "GridPreInit";
                behaviors.Sequence.GridInit = "GridInit";
                behaviors.Sequence.GridLoading = "GridLoading";
                behaviors.Sequence.GridLoaded = "GridLoaded";
                behaviors.Sequence.SequenceEnd = "SequenceEnd";
                behaviors.Sequence.SequenceUndefined = "SequenceUndefined";

                var defaultTimeline = [
                    behaviors.Sequence.SequenceInit,
                    behaviors.Sequence.GridPreInit,
                    behaviors.Sequence.GridInit,
                    behaviors.Sequence.GridLoading,
                    behaviors.Sequence.GridLoaded,
                    behaviors.Sequence.SequenceEnd
                ];

                function createTimeline() {
                    try {
                        // create a copy of the default timeline array
                        var timeline = defaultTimeline.slice(0);

                        return timeline;

                    } catch (e) {
                        vpGrid.logException(e);
                        return [];
                    }

                }

                //registered behaviors
                var timelineBehaviors = {};

                //private methods on Behaviors layer
                function timelineSequenceHasBehaviors(sequenceName) {
                    try {
                        if (isNotString(sequenceName)) {
                            return false;
                        }

                        if (sequenceName.isNullOrEmptyOrWhitespace()) {
                            return false;
                        }

                        if (isNullOrUndefinedOrEmpty(timelineBehaviors)) {
                            return false;
                        }

                        var sequenceNameBehaviors = timelineBehaviors[sequenceName];

                        if (isNullOrUndefinedOrEmpty(sequenceNameBehaviors)) {
                            return false;
                        }

                        return true;

                    } catch (e) {
                        //TODO : log
                        vpGrid.logException(e);
                        return false;
                    }
                }

                function timelineSequenceHasNoBehavior(sequenceName) {
                    return timelineSequenceHasBehaviors(sequenceName) === false;
                }

                function behaviorIsRegistered(sequenceName, handlerInfo) {
                    try {
                        if (timelineSequenceHasNoBehavior(sequenceName)) {
                            return false;
                        }

                        if (isNullOrUndefinedOrEmpty(handlerInfo)) {
                            return false;
                        }

                        if (isNotFunction(handlerInfo.execute)) {
                            //TODO : log
                            return false;
                        }

                        // get all behaviors for this sequence
                        var sequenceNameBehaviors = timelineBehaviors[sequenceName];
                        var behaviorsCount = sequenceNameBehaviors.length;

                        for (var i = 0; i < behaviorsCount; i++) {
                            if (sequenceNameBehaviors[i].execute === handlerInfo.execute) {
                                return true;
                            }
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                function registerBehavior(sequenceName, handlerInfo) {
                    /// <signature>
                    /// <summary>Register a behavior to be executed when executing the timeline sequence</summary>
                    /// <param name="sequenceName" type="String">the name of a sequence inside the execution timeline.</param>
                    /// <param name="handlerInfo" type="Object">A literal object of form {execute: function, isAsync : boolean}. 
                    ///     execute property is the function that will be called (the behavior) when executing the timeline's sequence. 
                    ///     isAsync property signals if the behavior executes itself asynchronous.
                    /// </param>
                    /// </signature>
                    try {
                        if (isNotString(sequenceName)) {
                            vpGrid.logError({
                                message: "Cannot register behavior : the sequence name is not a string"
                            });
                            return;
                        }
                        if (isNullOrUndefinedOrEmpty(handlerInfo)) {
                            vpGrid.logError({
                                message: "Cannot register behavior on sequence : '" + sequenceName + "'. Behavior Info is null or empty."
                            });
                            return;
                        }

                        if (isNotFunction(handlerInfo.execute)) {
                            vpGrid.logError({
                                message: "Cannot register behavior : behavior callback is not a function."
                            });
                            return;
                        }

                        // check if behavior has already been registered
                        if (behaviorIsRegistered(sequenceName, handlerInfo)) {
                            return;
                        }

                        //set isAsync property if not set
                        if (isNotBoolean(handlerInfo.isAsync)) {
                            handlerInfo.isAsync = false;
                        }

                        var sequenceNameBehaviors = timelineBehaviors[sequenceName];
                        // check first time registration
                        if (isNullOrUndefinedOrEmpty(sequenceNameBehaviors)) {
                            timelineBehaviors[sequenceName] = [];
                        }

                        timelineBehaviors[sequenceName].push(handlerInfo);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onTimelineCreated(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onTimelineCreated, vpGrid, eventArgs);

                        //TODO : check eventArgs corruption
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onTimelineCreated",
                                message: "eventArgs object corrupted by listener"
                            });
                            return;

                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.timeline)) {
                            vpGrid.logError({
                                functionName: "onTimelineCreated",
                                message: "eventArgs.timeline object corrupted by listener"
                            });
                            return;

                        }

                        //TODO : check that timeline is an array and contains only strings





                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                function onBehaviorsRegistration(timeline, eventName) {
                    try {
                        if (isNullOrUndefinedOrEmpty(timeline)) {
                            //TODO : log
                            return;
                        }
                        if (isNotString(eventName)) {
                            //TODO : log
                            return;
                        }

                        var timelineCount = timeline.length;
                        for (var i = 0; i < timelineCount; i++) {
                            var _sequenceName = timeline[i];
                            var eventArgs = {
                                sequenceName: _sequenceName,
                                behaviors: []
                            };
                            EventHandlers.raiseEvent(eventName, vpGrid, eventArgs);

                            if (isNullOrUndefinedOrEmpty(eventArgs.behaviors)) {
                                // no listeners or listeners that do nothing
                                continue;
                            }

                            // register behaviors given by listeners
                            var behaviorsCount = eventArgs.behaviors.length;
                            for (var j = 0; j < behaviorsCount; j++) {
                                registerBehavior(_sequenceName, eventArgs.behaviors[j]);
                            }
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function createExecutionSteps(timeline) {
                    try {
                        var steps = [];
                        if (isNullOrUndefinedOrEmpty(timeline)) {
                            vpGrid.logError({
                                functionName: "createExecutionSteps",
                                message: "timeline is empty : none of the behaviors will execute."
                            });
                            return;
                        }

                        var timelineCount = timeline.length;
                        for (var i = 0; i < timelineCount; i++) {
                            var _sequenceName = timeline[i];

                            // get behaviors registers for this sequence name
                            if (timelineSequenceHasNoBehavior(_sequenceName)) {
                                continue;
                            }
                            var _behaviors = timelineBehaviors[_sequenceName];
                            var behaviorsCount = _behaviors.length;
                            for (var j = 0; j < behaviorsCount; j++) {
                                var executionStep = {
                                    sequenceName: _sequenceName,
                                    behavior: _behaviors[j] // this property is a literal object like {isAsync : true|false, execute : function}
                                };
                                steps.push(executionStep);
                            } // end for

                        } // for (var i = 0; i < timelineCount; i++)

                        return steps;

                    } catch (e) {
                        vpGrid.logException(e);
                        return [];
                    }
                }

                function onTimelineExecuting(eventArgs) {
                    try {

                        //enable listeners to inspect and/or modify all execution steps
                        EventHandlers.raiseEvent(vpGrid.Event.onTimelineExecuting, vpGrid, eventArgs);

                        //TODO : check any corruption in eventArgs
                        //TODO : check any change in executionSteps

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function executeBehaviors(executionSteps) {
                    try {
                        if (isNullOrUndefinedOrEmpty(executionSteps)) {
                            //TODO : log
                            return;
                        }

                        function processNext() {
                            /// <signature>
                            /// <summary>Core execution engine of the timeline.
                            /// This engine is called multiple times until there is no behavior to execute
                            ///</summary>
                            /// </signature>
                            if (isNullOrUndefinedOrEmpty(executionSteps)) {
                                // there is no more step to execute
                                return;
                            }

                            var executionStep = executionSteps.shift();
                            //TODO : log execution step
                            // execute behavior
                            try {
                                // call the behavior and give him the callback method to call when its async processing is finished.
                                executionStep.behavior.execute(executionStep.sequenceName, processNext);
                                if (executionStep.behavior.isAsync) {
                                    // processNext will be called by the behavior itself
                                    return;
                                }

                                // let the UI update itself if needed
                                setTimeout(processNext, 0);

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        } // end function processNext()

                        //start execution engine
                        processNext();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                //public methods on this layer
                //behaviors.registerBehavior = registerBehavior;

                behaviors.timelineSequenceExists = function (sequenceName) {
                    try {
                        if (isNotString(sequenceName)) {
                            return false;
                        }

                        if (sequenceName.isInArray(behaviors.currentTimeline)) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                behaviors.timelineSequenceDoesNotExist = function (sequenceName) {
                    return behaviors.timelineSequenceExists(sequenceName) === false;
                }

                behaviors.getTimelineSequenceOnElement = function (element, defaultTimelineSequence, behaviorName) {
                    try {
                        var jqElement = $(element);

                        if (jqElement.notFound()) {
                            //TODO : log
                            return behaviors.Sequence.SequenceUndefined;
                        }

                        if (isNotString(behaviorName)) {
                            behaviorName = "undefined behavior";
                        }

                        if (isNotString(defaultTimelineSequence)) {
                            defaultTimelineSequence = behaviors.Sequence.GridInit;
                        }

                        var dataSequenceName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.TimelineSequence, "");
                        if (dataSequenceName.isNullOrEmptyOrWhitespace()) {
                            //TODO : log warning instead of error
                            vpGrid.logError({
                                message: "data attribute : " + vpGrid.HtmlDataTag.TimelineSequence + " is not defined on element : \n" + outerHtml(element),
                                info: "the following default value is applied to this data attribute: " + defaultTimelineSequence
                            });
                            dataSequenceName = defaultTimelineSequence;
                        }

                        if (behaviors.timelineSequenceDoesNotExist(dataSequenceName)) {
                            vpGrid.logError({
                                message: "data attribute value : " + vpGrid.HtmlDataTag.TimelineSequence + "='" + dataSequenceName + "' is not defined in the timeline. Target element : \n" + outerHtml(element),
                                info: "This value must be in [" + behaviors.currentTimeline.toString() + "]. Behavior " + behaviorName + " is not applied to this element."
                            });
                        }

                        return dataSequenceName;

                    } catch (e) {
                        vpGrid.logException(e);
                        return behaviors.Sequence.SequenceUndefined;
                    }
                }

                behaviors.executeTimeline = function () {
                    try {
                        var timeline = createTimeline();

                        //raise event to enable listeners to inspect and/or modify the timeline
                        var eventArgs = {
                            timeline: timeline
                        };
                        onTimelineCreated(eventArgs);

                        //make this timeline public
                        behaviors.currentTimeline = eventArgs.timeline;

                        //raise event onBehaviorsRegistering -> extension point to inject behaviors before internal behaviors
                        onBehaviorsRegistration(eventArgs.timeline, vpGrid.Event.onBehaviorsRegistering);

                        //inject internal behaviors
                        onBehaviorsRegistration(eventArgs.timeline, PrivateEvent.onBehaviorsRegistering);

                        //raise event onBehaviorsRegistered -> extension point to inject behaviors after internal behaviors
                        onBehaviorsRegistration(eventArgs.timeline, vpGrid.Event.onBehaviorsRegistered);

                        // get all execution steps
                        // an execution step is a behavior that will be executed at a specific point in the timeline
                        var executionSteps = createExecutionSteps(eventArgs.timeline);

                        //raise event onTimelineExecuting -> extension point to examine all execution steps in the timeline before they start executing
                        var eventArgs2 = {
                            executionSteps: executionSteps
                        };
                        onTimelineExecuting(eventArgs2);
                        executionSteps = eventArgs2.executionSteps;

                        //execute behaviors
                        executeBehaviors(executionSteps);

                    } catch (e) {
                        //TODO : log
                        vpGrid.logException(e);
                    }
                }

            } catch (e) {
                //error in  Behaviors layer
                vpGrid.logException(e);
            }
            finally {
                return behaviors;
            }
        })();
        //end Behaviors layer

        //internal behaviors definitions
        Behaviors.securityTrimmingBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior implements security trimming within the vpgrid-container. Security trimming is a way to hide UI elements when user is not in a defined role.</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    return;
                }

                if (isNotString(sequenceName)) {
                    vpGrid.logError({
                        message: "input sequenceName is not a string. SecurityTrimmingBehavior is aborted."
                    });
                    return;
                }

                //step 1 : find all UI elements that must be security trimmed in the sequence
                var selector = "[" + vpGrid.HtmlDataTag.securityTrimmed + "=true]";
                var jqElements = jqContainer.find(selector);
                if (jqElements.notFound()) {
                    return;
                }

                //step 2 : apply security trimming on each found elements
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    // check if security trimming must be applied on input sequenceName
                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridPreInit, "securityTrimmingBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }

                    //step 3 : by default hide this UI element
                    jqElement.hideEx();

                    //step 4 : raise event so that listeners can decide to trim or not to trim the element
                    var eventArgs = {
                        userIsInRole: false
                    };
                    var dataRoles = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.securityTrimmedRoles, "");
                    if (dataRoles.isNullOrEmptyOrWhitespace()) {
                        vpGrid.logError({
                            message: "data attribute : " + vpGrid.HtmlDataTag.securityTrimmedRoles + " is not defined on element : \n" + outerHtml(element)
                        });
                        dataRoles = "";
                    }

                    var roles = dataRoles.toArray(",");
                    eventArgs.roles = roles;

                    // ask listeners if user is in role
                    onSecurityTrimming(element, eventArgs);

                    //check if the userIsInRole has been setup
                    if (isNullOrUndefinedOrEmpty(eventArgs)) {
                        vpGrid.logError({
                            functionName: "securityTrimmingBehavior",
                            message: "eventArgs object corrupted by listener"
                        });
                        continue;
                    }

                    if (isNotBoolean(eventArgs.userIsInRole)) {
                        vpGrid.logError({
                            functionName: "securityTrimmingBehavior",
                            message: "eventArgs.userIsInRole boolean property corrupted by listener"
                        });
                        continue;
                    }

                    if (eventArgs.userIsInRole) {
                        // user is in role : element must be shown to user
                        jqElement.showEx();
                    }

                } // end for


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.securityTrimmingBehavior

        function onSecurityTrimming(element, eventArgs) {
            try {

                EventHandlers.raiseEvent(vpGrid.Event.onSecurityTrimming, element, eventArgs);

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        Behaviors.userInfoBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior builds a literal object that holds user infos needed for handling security and permissions </summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                vpGrid.currentUser = vpGrid.currentUser || {};

                if (vpGrid.options.enableUserInfo === false) {
                    // do not inject this behavior
                    return;
                }

                var userInfoUrl = vpGrid.options.userInfoUrl;
                if (isNullOrUndefinedOrEmpty(userInfoUrl)) {
                    vpGrid.logError({
                        functionName: "userInfoBehavior",
                        message: "UserInfo url is not set. UserInfo cannot be updated from server.",
                        info : "Check you have correctly setup the userInfoUrl in the options parameter passed to the vpGrid.init() method."
                    });
                }

                var ajaxOptions = {
                    dataType: "json",
                    url: userInfoUrl,
                    success: function (response) {
                        try {
                            //vpGrid.currentUser.name = response.data.name;
                            //vpGrid.currentUser.roles = response.data.roles;
                            //vpGrid.currentUser.login = response.data.login;
                            $.extend(vpGrid.currentUser, response.data);

                        } catch (e) {
                            vpGrid.logException(e);
                        }
                    }, // end success: function (data) {
                    complete: function (xhr, textStatus) {
                        try {
                            var eventArgs = {
                                userInfo: vpGrid.currentUser
                            };

                            onUserInfoReady(vpGrid, eventArgs);

                        } catch (e) {
                            vpGrid.logException(e);
                        }
                        finally {
                            
                        }
                    } // end complete: function (xhr, textStatus) {

                };

                $.extend(ajaxOptions, vpGridAjaxOptions);

                $.ajax(ajaxOptions);



            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.securityTrimmingBehavior


        function onUserInfoReady(element, eventArgs) {
            try {

                EventHandlers.raiseEvent(vpGrid.Event.onUserInfoReady, element, eventArgs);

            } catch (e) {
                vpGrid.logException(e);
            }
        };


        Behaviors.globalInfoBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior builds a literal object that holds global infos needed on the loaded grid.
            ///             
            ///          This literal object can be accessed at vpGrid.globalInfo      
            /// </summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                vpGrid.globalInfo = vpGrid.globalInfo || {};

                if (vpGrid.options.enableGlobalInfo === false) {
                    //do not inject this behavior
                    return;
                }

                var globalInfoUrl = vpGrid.options.globalInfoUrl;

                if (isNullOrUndefinedOrEmpty(globalInfoUrl)) {
                    vpGrid.logError({
                        functionName: "globalInfoBehavior",
                        message: "globalInfo url is not set. globalInfo cannot be updated from server.",
                        info: "Check you have correctly setup the globalInfoUrl in the options parameter passed to the vpGrid.init() method."
                    });
                }

                var ajaxOptions = {
                    dataType: "json",
                    url: globalInfoUrl,
                    success: function (response) {
                        try {
                            //vpGrid.currentUser.name = response.data.name;
                            //vpGrid.currentUser.roles = response.data.roles;
                            //vpGrid.currentUser.login = response.data.login;
                            $.extend(vpGrid.globalInfo, response.data);

                        } catch (e) {
                            vpGrid.logException(e);
                        }
                    }, // end success: function (data) {
                    complete: function (xhr, textStatus) {
                        try {
                            var eventArgs = {
                                globalInfo: vpGrid.globalInfo
                            };

                            onGlobalInfoReady(vpGrid, eventArgs);

                        } catch (e) {
                            vpGrid.logException(e);
                        }
                        finally {

                        }
                    } // end complete: function (xhr, textStatus) {

                };

                $.extend(ajaxOptions, vpGridAjaxOptions);

                $.ajax(ajaxOptions);



            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.securityTrimmingBehavior

        function onGlobalInfoReady(element, eventArgs) {
            try {

                EventHandlers.raiseEvent(vpGrid.Event.onGlobalInfoReady, element, eventArgs);

            } catch (e) {
                vpGrid.logException(e);
            }
        };



        Behaviors.DisableElementBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior disables any UI element that is configured to be disabled within the vpgrid-container.</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    //TODO : log info
                    return;
                }

                //step 1 : get all elements tagged with ui-disabled
                var elementsSelector = "[" + vpGrid.HtmlDataTag.UIDisabled + "=true]";
                var jqElements = $(elementsSelector);
                if (jqElements.notFound()) {
                    //TODO : log info
                    return;
                }

                // step 2 : take only elements that must be processed in this specific timeline sequence
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridLoading, "DataSourceBindingsBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }

                    applyDisabledStateOnElement(element);

                } // end for (var i = 0; i < elementsCount; i++)


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.DisableElementBehavior

        Behaviors.ActiveHeaderBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior implements active header within the vpgrid-container.
            /// Active header is a column header that toggles itself to a button on hoovering.
            ///</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    //TODO : log info
                    return;
                }

                //step 1 : get all elements tagged with ui-element
                var elementsSelector = "[role=" + vpGrid.HtmlRoleAttribute.ActiveHeader + "][" + vpGrid.HtmlDataTag.UIElement + "=true]";
                var jqElements = $(elementsSelector);
                if (jqElements.notFound()) {
                    //TODO : log info
                    return;
                }

                // step 2 : take only elements that must be processed in this specific timeline sequence
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridLoading, "DataSourceBindingsBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }

                    applyActiveHeaderOnElement(element);

                } // end for (var i = 0; i < elementsCount; i++)


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.ActiveHeaderBehavior

        Behaviors.DataSourceBindingsBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior implements data source binding within the vpgrid-container.</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    //TODO : log info
                    return;
                }

                //step 1 : get all elements tagged with ui-element
                var elementsSelector = "[" + vpGrid.HtmlDataTag.UIElement + "=true]";
                var jqElements = $(elementsSelector);
                if (jqElements.notFound()) {
                    //TODO : log info
                    return;
                }

                // step 2 : take only elements that must be processed in this specific timeline sequence
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridLoading, "DataSourceBindingsBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }


                    //check if ui element must bind to a data source
                    var dataSource = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSource, "");

                    if (dataSource.isNotNullOrEmptyOrWhitespace()) {
                        bindDataSourceOnElement(element);
                    }

                } // end for (var i = 0; i < elementsCount; i++)


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.DataSourceBindingsBehavior

        Behaviors.UIWidgetsBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior implements jQuery-ui widgets binding within the vpgrid-container.</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    return;
                }

                //step 1 : get all elements tagged with ui-widget
                var elementsSelector = "[" + vpGrid.HtmlDataTag.UIWidget + "]";
                var jqElements = $(elementsSelector);
                if (jqElements.notFound()) {
                    //TODO : log info
                    return;
                }

                // step 2 : take only elements that must be processed in this specific timeline sequence
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridLoading, "UIWidgetsBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }

                    bindWidgetOnElement(element);
                }


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.UIWidgetsBehavior

        Behaviors.BindHandlersBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior implements event handlers binding within the vpgrid-container.</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    //TODO : log
                    return;
                }

                //step 1 : get all elements tagged with data-vpgrid-handlers
                var elementsSelector = "[" + vpGrid.HtmlDataTag.Handlers + "]";
                var jqElements = $(elementsSelector);
                if (jqElements.notFound()) {
                    //TODO : log info
                    return;
                }

                // step 2 : take only elements that must be processed in this specific timeline sequence
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridLoading, "BindHandlersBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }

                    bindHandlersOnElement(element);
                }


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.BindHandlersBehavior

        Behaviors.FillContentPlaceholderBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior implements content injection within the vpgrid-container.</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    //TODO : log
                    return;
                }

                //step 1 : get all elements tagged with data-vpgrid-ui-content-placeholder
                var elementsSelector = "[" + vpGrid.HtmlDataTag.UIContentPlaceholder + "=true]";
                var jqElements = $(elementsSelector);
                if (jqElements.notFound()) {
                    //TODO : log info
                    return;
                }

                // step 2 : take only elements that must be processed in this specific timeline sequence
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridLoaded, "FillContentPlaceholderBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }

                    fillContentPlaceholderOnElement(element);
                }


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.BindHandlersBehavior

        Behaviors.GridInitBehavior = function (sequenceName, timelineExecutionCallback) {
            /// <signature>
            /// <summary>This behavior implements jqGrid configuration and instanciation</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// <param name="sequenceName" type="Function">Core timeline execution engine to be called when execution of this behavior is async</param>
            /// </signature>
            try {
                JQGrid.init();

            } catch (e) {
                vpGrid.logException(e);
            }

        };

        Behaviors.GridLoadBehavior = function (sequenceName, timelineExecutionCallback) {
            /// <signature>
            /// <summary>This behavior implements jqGrid data loading</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// <param name="sequenceName" type="Function">Core timeline execution engine to be called back when execution of this behavior is async</param>
            /// </signature>
            try {
                if (vpGrid.options && vpGrid.options.loadGridOnPageLoad === false) {
                    JQGrid.hasLoaded = true;
                    timelineExecutionCallback();
                    return;
                }

                JQGrid.loadData(timelineExecutionCallback);

            } catch (e) {
                vpGrid.logException(e);
            }

        };

        Behaviors.GridLoadedBehavior = function (sequenceName, timelineExecutionCallback) {
            /// <signature>
            /// <summary>This behavior implements jqGrid configuration after data is loaded</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// <param name="sequenceName" type="Function">Core timeline execution engine to be called back when execution of this behavior is async</param>
            /// </signature>
            try {
                JQGrid.bindAutocompleteOnSearchInputs();

            } catch (e) {
                vpGrid.logException(e);
            }

        };

        //end internal behaviors definitions

        //private Eventhandlers
        var PrivateEventHandlers = {};
        PrivateEventHandlers.injectInternalBehaviors = function (source, eventArgs) {
            try {
                if (isNullOrUndefined(eventArgs)) {
                    //TODO : log
                    return;
                }

                var _sequenceName = eventArgs.sequenceName;
                if (isNotString(_sequenceName)) {
                    //TODO : log
                    return;
                }

                //register securityTrimming behavior at all steps
                eventArgs.behaviors.push(
                    {
                        execute: Behaviors.securityTrimmingBehavior,
                        isAsync: false
                    });

                //register UIElements behavior at all steps
                eventArgs.behaviors.push(
                        {
                            execute: Behaviors.DataSourceBindingsBehavior,
                            isAsync: false
                        });

                eventArgs.behaviors.push(
                        {
                            execute: Behaviors.ActiveHeaderBehavior,
                            isAsync: false
                        });

                //register UIWidgets behavior at all steps
                eventArgs.behaviors.push(
                        {
                            execute: Behaviors.UIWidgetsBehavior,
                            isAsync: false
                        });

                //register BindHandlers behavior at all steps
                eventArgs.behaviors.push(
                        {
                            execute: Behaviors.BindHandlersBehavior,
                            isAsync: false
                        });

                //register DisableElement behavior at all steps
                eventArgs.behaviors.push(
                        {
                            execute: Behaviors.DisableElementBehavior,
                            isAsync: false
                        });


                if (_sequenceName === Behaviors.Sequence.GridPreInit) {
                    eventArgs.behaviors.push(
                        {
                            execute: Behaviors.userInfoBehavior,
                            isAsync: false
                        });

                    eventArgs.behaviors.push(
                        {
                            execute: Behaviors.globalInfoBehavior,
                            isAsync: false
                        });

                }

                if (_sequenceName === Behaviors.Sequence.GridInit) {
                    eventArgs.behaviors.push(
                        {
                            execute: Behaviors.GridInitBehavior,
                            isAsync: false
                        });

                }

                if (_sequenceName === Behaviors.Sequence.GridLoading) {
                    eventArgs.behaviors.push(
                        {
                            execute: Behaviors.GridLoadBehavior,
                            isAsync: true
                        });
                }

                if (_sequenceName === Behaviors.Sequence.GridLoaded) {
                    eventArgs.behaviors.push(
                        {
                            execute: Behaviors.GridLoadedBehavior,
                            isAsync: false
                        });
                }


            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function registerPrivateHandlers() {
            try {

                vpGrid.registerEventHandler(PrivateEvent.onBehaviorsRegistering, PrivateEventHandlers.injectInternalBehaviors)

            } catch (e) {
                vpGrid.logException(e);
            }

        };

        function onModalDialogClosed(element, eventArgs) {
            try {
                if (isNullOrUndefinedOrEmpty(element)) {
                    vpGrid.logError({
                        functionName: "onModalDialogClosed",
                        message: "input element is null or empty or undefined",
                        info: "listeners to this event are not called"
                    });
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    vpGrid.logError({
                        functionName: "onModalDialogClosed",
                        message: "Input element not found \n: " + outerHtml(element)
                    });
                    return;
                }

                if (isNullOrUndefined(eventArgs)) {
                    eventArgs = {};
                }

                var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, "");
                if (dialogId.isNullOrEmptyOrWhitespace()) {
                    vpGrid.logError({
                        functionName: "onModalDialogClosed",
                        message: "data attribute : " + vpGrid.HtmlDataTag.DialogId + " is not defined on element \n: " + outerHtml(element)
                    });
                }

                eventArgs.dialogId = dialogId;

                EventHandlers.raiseEvent(vpGrid.Event.onModalDialogClosed, element, eventArgs);

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function onFileuploading(source, eventArgs) {
            try {
                // make a backup copy of eventArgs
                var eventArgsCopy = $.extend({}, eventArgs);

                EventHandlers.raiseEvent(vpGrid.Event.onFileuploading, source, eventArgs);

                // check possible misbehavior from listeners
                if (isNullOrUndefinedOrEmpty(eventArgs)) {
                    vpGrid.logError({
                        functionName: "onFileuploading",
                        message: "eventArgs object corrupted by listener",
                        info: "eventArgs object is reverted to its original state"
                    });
                    $.extend(eventArgs, eventArgsCopy);
                    return;
                }

                if (isNullOrUndefinedOrEmpty(eventArgs.formData)) {
                    eventArgs.formData = eventArgsCopy.formData;
                }


            } catch (e) {
                vpGrid.logException(e);
            }
        }

        function onFormValidating(source, eventArgs) {
            try {
                // make a backup copy of eventArgs
                var eventArgsCopy = $.extend({}, eventArgs);

                EventHandlers.raiseEvent(vpGrid.Event.onFormValidating, source, eventArgs);

                // check possible misbehavior from listeners
                if (isNullOrUndefinedOrEmpty(eventArgs)) {
                    vpGrid.logError({
                        functionName: "onFormValidating",
                        message: "eventArgs object corrupted by listener",
                        info: "eventArgs object is reverted to its original state"
                    });
                    $.extend(eventArgs, eventArgsCopy);
                    return;
                }

                if (isNotBoolean(eventArgs.isValid)) {
                    vpGrid.logError({
                        functionName: "onFormValidating",
                        message: "eventArgs.isValid property corrupted by listener",
                        info: "eventArgs.isValid value is reverted to its original state"
                    });
                    eventArgs.isValid = true;
                    return;
                }


            } catch (e) {
                vpGrid.logException(e);
            }
        }


        function onModalDialogOpening(source, eventArgs) {
            try {
                // make a backup copy of eventArgs
                var eventArgsCopy = $.extend({}, eventArgs);

                EventHandlers.raiseEvent(vpGrid.Event.onModalDialogOpening, source, eventArgs);

                // check possible misbehavior from listeners
                if (isNullOrUndefinedOrEmpty(eventArgs)) {
                    vpGrid.logError({
                        functionName: "onModalDialogOpening",
                        message: "eventArgs object corrupted by listener",
                        info: "eventArgs object is reverted to its original state"
                    });
                    $.extend(eventArgs, eventArgsCopy);
                    return;
                }

                if (isNotBoolean(eventArgs.cancel)) {
                    vpGrid.logError({
                        functionName: "onModalDialogOpening",
                        message: "eventArgs.cancel property corrupted by listener",
                        info: "eventArgs.cancel value is reverted to its original state"
                    });
                    eventArgs.cancel = false;
                    return;
                }


            } catch (e) {
                vpGrid.logException(e);
            }
        }

        function onModalDialogOpened(source, eventArgs) {
            try {
                // make a backup copy of eventArgs
                var eventArgsCopy = $.extend({}, eventArgs);

                EventHandlers.raiseEvent(vpGrid.Event.onModalDialogOpened, source, eventArgs);

                // check possible misbehavior from listeners
                if (isNullOrUndefinedOrEmpty(eventArgs)) {
                    vpGrid.logError({
                        functionName: "onModalDialogOpened",
                        message: "eventArgs object corrupted by listener",
                        info: "eventArgs object is reverted to its original state"
                    });
                    $.extend(eventArgs, eventArgsCopy);
                    return;
                }


            } catch (e) {
                vpGrid.logException(e);
            }
        }

        function onUIElementDisabling(source, eventArgs) {
            try {
                // make a backup copy of eventArgs
                var eventArgsCopy = $.extend({}, eventArgs);

                EventHandlers.raiseEvent(vpGrid.Event.onUIElementDisabling, source, eventArgs);

                // check possible misbehavior from listeners
                if (isNullOrUndefinedOrEmpty(eventArgs)) {
                    vpGrid.logError({
                        functionName: "onUIElementDisabling",
                        message: "eventArgs object corrupted by listener",
                        info: "eventArgs object is reverted to its original state"
                    });
                    $.extend(eventArgs, eventArgsCopy);
                    return;
                }

                if (isNotBoolean(eventArgs.cancel)) {
                    vpGrid.logError({
                        functionName: "onUIElementDisabling",
                        message: "eventArgs.cancel property corrupted by listener",
                        info: "eventArgs.cancel value is reverted to its original state"
                    });
                    eventArgs.cancel = false;
                    return;
                }


            } catch (e) {
                vpGrid.logException(e);
            }
        }

        function onUIElementEnabling(source, eventArgs) {
            try {
                // make a backup copy of eventArgs
                var eventArgsCopy = $.extend({}, eventArgs);

                EventHandlers.raiseEvent(vpGrid.Event.onUIElementEnabling, source, eventArgs);

                // check possible misbehavior from listeners
                if (isNullOrUndefinedOrEmpty(eventArgs)) {
                    vpGrid.logError({
                        functionName: "onUIElementEnabling",
                        message: "eventArgs object corrupted by listener",
                        info: "eventArgs object is reverted to its original state"
                    });
                    $.extend(eventArgs, eventArgsCopy);
                    return;
                }

                if (isNotBoolean(eventArgs.cancel)) {
                    vpGrid.logError({
                        functionName: "onUIElementEnabling",
                        message: "eventArgs.cancel property corrupted by listener",
                        info: "eventArgs.cancel value is reverted to its original state"
                    });
                    eventArgs.cancel = false;
                    return;
                }


            } catch (e) {
                vpGrid.logException(e);
            }
        }

        function onWindowClosing(source, eventArgs) {
            try {
                // make a backup copy of eventArgs
                var eventArgsCopy = $.extend({}, eventArgs);

                EventHandlers.raiseEvent(vpGrid.Event.onWindowClosing, source, eventArgs);

                // check possible misbehavior from listeners
                if (isNullOrUndefinedOrEmpty(eventArgs)) {
                    vpGrid.logError({
                        functionName: "onWindowClosing",
                        message: "eventArgs object corrupted by listener",
                        info: "eventArgs object is reverted to its original state"
                    });
                    $.extend(eventArgs, eventArgsCopy);
                    return;
                }

                if (isNotBoolean(eventArgs.cancel)) {
                    vpGrid.logError({
                        functionName: "onWindowClosing",
                        message: "eventArgs.cancel property corrupted by listener",
                        info: "eventArgs.cancel value is reverted to its original state"
                    });
                    eventArgs.cancel = false;
                    return;
                }


            } catch (e) {
                vpGrid.logException(e);
            }
        }

        // end vpGrid Events

        // jqGrid layer
        var JQGrid = (function () {
            var jqGrid = {};
            try {
                jqGrid.options = {
                    datatype: "local",
                    //height: 275,    // 12 rows
                    height: 390,    // 17 rows
                    //height: 181,    // 8 rows
                    //width: 500,
                    autowidth: true,
                    shrinkToFit: true,
                    ignoreCase: true,
                    altRows: false,
                    loadonce: true, //all data is loaded locally
                    rowNum: 10,
                    caption: '',
                    multiselect: true,
                    multiboxonly: true,
                    hidegrid: false,
                    cellEdit: true,
                    cellsubmit: 'clientArray',
                    gridview: true,
                    viewrecords: false,
                    toolbar: [true, "bottom"], // bottom toolbar is used as a status bar only
                    headertitles: true,
                    footerrow: false,
                    hoverrows: false,
                    direction: "ltr",
                    sortable: false, //column reordering

                    // add-on for vpGrid
                    rowHeight: 23,  // one row in jqGrid is 23 pixels height
                    minColWidth: 60,
                    toprow: false, // summary row below jqGrid headers
                    numberOfSummaryRows: 1,
                    autoInsertNewLineAtBottom: true
                };

                jqGrid.Id = "vpGridExcel";
                jqGrid.remoteOperationPending = false;

                jqGrid.hasLoaded = false;
                jqGrid.hasReceivedDataFromRemote = false;

                // total number of items loaded in the grid from remote server
                // this filed is updated by jqGrid.loadDataFromWebResponse function
                jqGrid.totalItemCount = 0;

                // total number of items seen in the grid by filtering through the search filter toolbar
                // this field is update by jqGrid.rows function
                jqGrid.filteredItemCount = 0;

                jqGrid.hasFrozenColumns = false;
                jqGrid.hasLockedColumns = false;
                jqGrid.hasNewRowInsertedAtBottom = false;

                jqGrid.currentRowId = null;

                jqGrid.applyDataTagForColNamesOnRow = function (row) {
                    /// <signature>
                    /// <summary>Add the data tag data-vpgrid-column-name in all cells of the input row.</summary>
                    /// <param name="row" type="Object">Dom element representing a row in the grid.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        jqRow = $(row);

                        if (jqRow.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.applyDataTagForColNamesOnRow",
                                message: "row not found : " + outerHtml(row)
                            });
                            return;
                        }

                        var cellsSelector = "td[role=gridcell]";
                        var jqCells = jqRow.find(cellsSelector);
                        var jqCellsCount = jqCells.length;
                        for (var i = 0; i < jqCellsCount; i++) {
                            var cell = jqCells[i];
                            var jqCell = $(cell);
                            var colName = jqCell.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                            // check if the data tag has already been applied
                            if (isNotNullOrUndefinedOrEmpty(colName)) {
                                continue;
                            }

                            //happens when user has filtered the grid
                            // try a fallback technique by using the TD index
                            colName = jqGrid.colNameAtCellIndex(jqCell.index());
                            if (colName !== null) {
                                jqCell.attr(vpGrid.HtmlDataTag.ColumnName, colName);
                            }

                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.options.beforeSelectRow = function (rowid, e) {
                    try {
                        //update current selected row
                        jqGrid.currentRowId = rowid;

                        var target = e.target;
                        var cellSelector = "td[role=gridcell]";
                        var jqElement = $(target).closest(cellSelector);

                        if (jqElement.notFound()) {
                            // check for summary row
                            var cellSelector2 = "td[role=summarygridcell]";
                            jqElement = $(target).closest(cellSelector2);
                            
                            if (jqElement.found()) {
                                //prevent cell editing on summary row
                                return false;
                            }
                        }

                        if (jqElement.notFound()) {
                            vpGrid.logError({
                                message: "Selector not found : '" + cellSelector + "'",
                                functionName: "jqGrid.options.beforeSelectRow",
                                info: "Check that '" + cellSelector + "'" + " is parent of element :\n" + outerHtml(target)

                            });
                            return true; // allow row selection
                        }

                        var rowSelector = "tr[role=row]";
                        var jqRow = $(target).closest(rowSelector);
                        if (jqRow.notFound()) {
                            vpGrid.logError({
                                message: "Selector not found : '" + rowSelector + "'",
                                functionName: "jqGrid.options.beforeSelectRow",
                                info: "Check that '" + rowSelector + "'" + " is parent of element :\n" + outerHtml(target)

                            });
                            return true; // allow row selection
                        }

                        jqGrid.applyDataTagForColNamesOnRow(jqRow[0]);

                        //extract colName to check if the TD is tagged with the data-vpgrid-column-name
                        var colName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                        
                        if (isNullOrUndefinedOrEmpty(colName)) {
                            //colname was not found
                            vpGrid.logError({
                                message: "Colname not found in attributes of : '" + cellSelector + "'",
                                functionName: "jqGrid.options.beforeSelectRow",
                                info: "Check attributes on element : \n" + outerHtml(jqElement[0])

                            });
                            return true; // allow row selection
                        }

                        //Check if the row is readonly
                        var rowIsReadOnly = true;
                        if (jqGrid.canUpdateRowWithId(rowid)) {
                            rowIsReadOnly = false;
                        }

                        if (rowIsReadOnly === true) {
                            //TODO : log
                            var message = vpGrid.UIString.rowIsReadOnly;
                            vpGrid.showUINotificationAtElement(target, "", message);
                            return false;
                        }


                        //raise event to let listeners block row edition
                        var data = jqGrid.rowData(rowid);
                        var eventArgs = {
                            rowId: rowid,
                            rowData: data,
                            cancel: false,
                            cancelReason: ""
                        };


                        onRowEditing(target, eventArgs);

                        if (isNullOrUndefinedOrEmpty(eventArgs.cancelReason))   {
                            eventArgs.cancelReason = vpGrid.UIString.rowIsReadOnly;
                        }

                        if (eventArgs.cancel === true) {
                            //var selector = 'tr[id=' + rowid + ']';
                            vpGrid.showUINotificationAtElement(target, "", eventArgs.cancelReason);
                            return false;
                        }

                        var colModel = jqGrid.colModelOf(colName);

                        //raise event onCellEditing
                        var eventArgs2 = {
                            rowId: rowid,
                            rowData: data,
                            cellName:colName,
                            cancel: false,
                            cancelReason: ""
                        };

                        //raise event only if the cell is editable
                        if (colModel.editable === true) {
                            onCellEditing(target, eventArgs2);
                        }
                        
                        if (isNullOrUndefinedOrEmpty(eventArgs2.cancelReason))   {
                            eventArgs2.cancelReason = vpGrid.UIString.cellIsReadOnly;
                        }

                        if (eventArgs2.cancel === true) {
                            //var selector = 'tr[id=' + rowid + ']';
                            vpGrid.showUINotificationAtElement(target, "", eventArgs2.cancelReason);
                            return false;
                        }


                        if (colModel.isDeleteAction) {
                            jqElement.click(function (event) {
                                try {
                                    if (event) {
                                        if (event.preventDefault) {
                                            event.preventDefault();
                                        }
                                        if (event.stopPropagation) {
                                            event.stopPropagation()
                                        }
                                    }
                                    if (jqGrid.canDeleteRowWithId(rowid)) {
                                        showDeleteItemMessage(rowid);
                                        return;
                                    }

                                    showCannotDeleteItemMessage(rowid);
                                    

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            });
                            //fire the event
                            executeAsync(jqElement[0], function () {
                                jqElement.click();
                            });

                            return true;
                        }

                        if (colModel.editable === false) {
                            vpGrid.showUINotificationAtElement(target, "", vpGrid.UIString.columnIsNotEditable);
                        }

                        return true; // allow row selection

                    } catch (e) {
                        vpGrid.logException(e);
                        return true; // allow row selection
                    }

                }

                jqGrid.options.beforeRenderingCell = function (rowid, value, rawObject, colModel, rowData) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners inject custom attributes (style/title/class/...) on the td cell element that jqGrid is about to render.</summary>
                    /// <param name="rowid" type="String">The id of the row</param>
                    /// <param name="value" type="String">Value of the cell being rendered by jqGrid</param>
                    /// <param name="rawObject" type="Object">????</param>
                    /// <param name="colModel" type="Object">Column model of the cell</param>
                    /// <param name="rowData" type="Object">Literal object containing column values. Each property is the name of the corresponding column (as set in the column model).</param>
                    /// <returns type="String">Returns all attributes serialized as one string.</returns>
                    /// </signature>
                    try {

                        //var data = rowData; //rowData is partially constructed and does not contain columns placed after this column
                        var data = rawObject;
                        var cellName = colModel.name;

                        if ( cellName.isNotCustomPropertyOf(rowData)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.beforeRenderingCell",
                                message: "Cannot find property named : '" + cellName + "' within input object rowData. rowid : '" + rowid + "'"
                            });
                        }
                        var cellValue = rowData[cellName];

                        var eventArgs = {
                            cellName: cellName,
                            cellValue: cellValue, //do not take value input parameter because it is a formatted value
                            rowData: data,
                            td: {}
                        };

                        //raise event to enable listeners set attributes on the <td> element
                        onCellRendering(eventArgs);

                        //TODO : if listeners have done nothing : augment eventArgs when min and max value is set on colModel and current Value is out of range
                        if (vpGrid.options && vpGrid.options.showUIStateErrorsOnCellRendering === true &&
                            jqGrid.cellValueIsOutOfRange(rowid, cellName, cellValue, colModel)) {
                            if (isNullOrUndefinedOrEmpty(eventArgs.td['class'])) {
                                eventArgs.td['class'] = "";
                            }

                            eventArgs.td['class'] += " ui-state-error";

                        }
                        
                        var htmlAttributes = "";
                        if (isString(eventArgs.td.title)) {
                            htmlAttributes += (' title="' + eventArgs.td.title.toEncodedHTML() + '"');
                        }

                        if (isString(eventArgs.td['class'])) {
                            htmlAttributes += (' class="' + eventArgs.td['class'] + '"');
                        }

                        if (isString(eventArgs.td.style)) {
                            htmlAttributes += (' style="' + eventArgs.td.style + '"');
                        }

                        //inject colName in data-tag attribute
                        //htmlAttributes += (' data-vpgrid-column-name="' + cellName + '"');

                        //TODO : check if listeners have injected other html attributes

                        return htmlAttributes;


                    } catch (e) {
                        vpGrid.logException(e);
                        return "";
                    }

                }

                jqGrid.options.beforeEditCell = function (rowid, cellname, value, iRow, iCol) {
                    try {

                        //update current selected row
                        jqGrid.currentRowId = rowid;

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : beforeEditCell is stopped. rowid='" + rowid + "'" + "; cellName='" + cellname + "'"
                            });
                            return;
                        }

                        var colModel = colModels[iCol];

                        var editType = colModel.edittype;
                        if (isNullOrUndefinedOrEmpty(editType)) {
                            return;
                        }

                        var data = jqGrid.rowData(rowid);

                        var eventArgs = {
                            cellName: cellname,
                            cellValueBeforeEditing: value,
                            rowData: data,
                            selectOptions : []
                        };

                        //check if column type = year
                        // this type of column is rendered as a select list
                        if (colModel.isYear) {
                            var years = [];
                            var now = new Date();
                            colModel.editrules = colModel.editrules || {};
                            var minYear = colModel.editrules.minValue;
                            var maxYear = colModel.editrules.maxValue;
                            years.addRangeOfIntegers(minYear, maxYear);
                            var itemCount = years.length;
                            for (var i = 0; i < itemCount; i++) {
                                eventArgs.selectOptions.push({
                                    key: years[i],
                                    value : years[i]
                                });
                            } // end for
                            //raise event to enable listeners to inspect and/or to inject values for the select tag
                            onSelectCellRendering(colModel, eventArgs);
                            return;
                        }

                        if (editType === "select") {

                            //check for default select options
                            if (colModel.hasDefaultSelectOptions === true) {
                                try {
                                    var serializedOptions = colModel.editoptions.defaultValue;
                                    var selectOptions = serializedOptions.split(";");
                                    if (selectOptions.length === 1) {
                                        vpGrid.logError({
                                            functionName: 'jqGrid.options.beforeEditCell',
                                            message: "Column : '" + colModel.name + "' has invalid select options defined : '" + serializedOptions + "'",
                                            info : "Select options on the data tag attribute " +  vpGrid.HtmlDataTag.selectOptions +  " should have the format : key1:text1;key2:text2;...;keyN:textN"
                                        });
                                    }
                                    for (var i = 0; i < selectOptions.length; i++) {
                                        var selectOption = selectOptions[i];
                                        var keyValue = selectOption.split(":");
                                        eventArgs.selectOptions.push({
                                            key: keyValue[0],
                                            value: keyValue[1]
                                        });
                                    }

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                                
                            }

                            //raise event to enable listeners to inspect and/or to inject values for the select tag
                            onSelectCellRendering(colModel, eventArgs);
                            return;
                        }

                        //TODO : Process other input types

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                jqGrid.options.afterEditCell = function (rowid, cellname, value, iRow, iCol) {
                    try {
                        jqGrid.currentRowId = rowid;

                        // find the cell
                        var jqGridHost = jqGrid.host();
                        // first step : find the row where the cell is in edit mode
                        var rowSelector = "tr[role=row][id=" + rowid + "]";
                        var jqRow = jqGridHost.find(rowSelector);
                        // second step : find the cell in edit mode
                        var cellSelector = jqGrid.cellSelectorForCol(cellname);
                        var jqCell = jqRow.find(cellSelector);
                        if (jqCell.notFound()) {
                            vpGrid.logError({
                                message: "Cell not found in DOM. rowid='" + rowid + "'" + "; cellName='" + cellname + "'"
                            });
                        }

                        //third step : find the input element (either input or select or textarea)
                        var jqInput = jqCell.find("input");
                        var jqSelect = jqCell.find("select");
                        var jqTextArea = jqCell.find("textarea");

                        if (jqInput.notFound() && jqSelect.notFound() && jqTextArea.notFound()) {
                            vpGrid.logError({
                                message: "Input element or Select or Textarea not found in DOM. rowid='" + rowid + "'" + "; cellName='" + cellname + "'"
                            });
                            return;
                        }

                        //adjust the width of the input field
                        jqSelect.width(jqSelect.parent().width());
                        jqSelect.addClass('vpgrid-input-field');

                        //Add CSS class for input text field
                        if (jqInput.isInputText()) {
                            jqInput.addClass('vpgrid-input-field');
                        }

                        //adjust overflow for textarea
                        jqTextArea.addClass('vpgrid-input-field');
                        jqTextArea.parent().css('overflow', 'visible');
                        if (jqTextArea.found()) {
                            var test = $('<textarea>');
                            test.css('resize', 'both');

                            if (test.css('resize') !== 'both') {
                                jqTextArea.resizable({
                                    handles: "se"
                                });
                            }
                        }


                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : rowid='" + rowid + "'" + "; cellName='" + cellname + "'"
                            });
                            return;
                        }

                        var colModel = colModels[iCol];
                        if (isNullOrUndefinedOrEmpty(colModel)) {
                            vpGrid.logError({
                                message: "ColModel not found :  rowid='" + rowid + "'" + "; cellName='" + cellname + "'" + "; iCol='" + iCol + "'"
                            });
                            return;
                        }


                        if (colModel.isAutocomplete) {
                            // input is an autocomplete field
                            //bindEventsOnInputDateEditing(jqInput,rowid iRow, iCol);
                            bindEventsOnInputAutocompleteEditing(jqInput, rowid, iRow, iCol);
                            // bind autocomplete widget
                            jqGrid.options.bindAutocompleteCell(rowid,jqInput, value, cellname, iRow, iCol);
                            // do a click to show the full list of autocomplete values
                            executeAsync(this,function () {
                                try {
                                    jqInput.click();
                                } catch (e) {
                                    vpGrid.logException(e);
                                }

                            }, 200);

                            return;
                        }


                        if (colModel.isDate) {
                            // input is a date field
                            bindEventsOnInputDateEditing(jqInput,rowid, iRow, iCol);
                            // bind datepicker widget
                            var datepickerOptions = vpGrid.options.datepickerOptions;
                            if (isNullOrUndefined(datepickerOptions)) {
                                datepickerOptions = {};
                            }
                            //TODO : raise event so that listeners can inspect and/or modifiy datepicker options for this cell

                            // Autosave cell on datepicker closed
                            datepickerOptions.onClose = function (selectedDate) {
                                try {
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            };

                            jqInput.datepicker(datepickerOptions);
                            return;
                        }

                        if (colModel.isYear) {
                            bindEventsOnSelectEditing(jqSelect, rowid, iRow, iCol);
                            return;
                        }


                        if (colModel.isSelect) {
                            bindEventsOnSelectEditing(jqSelect, rowid, iRow, iCol);
                            return;
                        }

                        if (colModel.isNote) {
                            bindEventsOnTextAreaEditing(jqTextArea, rowid, iRow, iCol);
                            return;
                        }

                        if (colModel.isInteger) {
                            //set input field content  with a localized value
                            //TODO : extract following lines into a separate method
                            var customFormatterOptions = {};
                            customFormatterOptions.integer = {};
                            var customIntegerFormatterOptions = customFormatterOptions.integer;
                            customIntegerFormatterOptions.thousandsSeparator = colModel.formatoptions.thousandsSeparator;

                            var localeValue = $.fn.fmatter("integer", value, customFormatterOptions);
                            
                            jqInput.val(localeValue);
                            //TODO : end extract

                            bindEventsOnIntegerEditing(jqInput, rowid, iRow, iCol);
                            return;
                        }

                        if (colModel.isCurrency) {

                            //set input field content  with a localized value
                            //TODO : extract following lines into a separate method
                            var customFormatterOptions = {};
                            customFormatterOptions.currency = {};
                            var customCurrencyFormatterOptions = customFormatterOptions.currency;
                            customCurrencyFormatterOptions.decimalSeparator = colModel.formatoptions.decimalSeparator;
                            customCurrencyFormatterOptions.thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            customCurrencyFormatterOptions.decimalPlaces = colModel.formatoptions.decimalPlaces;

                            var localeValue = $.fn.fmatter("currency", value, customFormatterOptions);
                            
                            jqInput.val(localeValue);
                            //TODO : end extract

                            bindEventsOnCurrencyEditing(jqInput, rowid, iRow, iCol);
                            return;
                        }

                        if (colModel.isNumber) {
                            //set input field content  with a localized value
                            //TODO : extract following lines into a separate method
                            var customFormatterOptions = {};
                            customFormatterOptions.number = {};
                            var customNumberFormatterOptions = customFormatterOptions.number;
                            customNumberFormatterOptions.decimalSeparator = colModel.formatoptions.decimalSeparator;
                            customNumberFormatterOptions.thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            customNumberFormatterOptions.decimalPlaces = colModel.formatoptions.decimalPlaces;

                            var localeValue = $.fn.fmatter("number", value, customFormatterOptions);
               
                            jqInput.val(localeValue);
                            //TODO : end extract

                            bindEventsOnNumberEditing(jqInput, rowid, iRow, iCol);
                            return;
                        }

                        

                        // bind events on other type of inputs (checkbox/text ...)
                        bindEventsOnInputEditing(jqInput, rowid, iRow, iCol);

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                jqGrid.options.beforeSaveCell = function (rowid, cellname, value, iRow, iCol) {
                    try {
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : rowid='" + rowid + "'" + "; cellName='" + cellname + "'"
                            });
                            return value;
                        }

                        var colModel = colModels[iCol];
                        if (isNullOrUndefinedOrEmpty(colModel)) {
                            vpGrid.logError({
                                message: "ColModel not found :  rowid='" + rowid + "'" + "; cellName='" + cellname + "'" + "; iCol='" + iCol + "'"
                            });
                            return value ;
                        }

                        var sanitizedValue = value;

                        if (colModel.isCurrency && value !== undefined) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            var decimalSeparator = colModel.formatoptions.decimalSeparator;
                            sanitizedValue = value.replaceAll(thousandsSeparator, "");
                            sanitizedValue = sanitizedValue.replaceAll(decimalSeparator, '.');
                        }

                        if (colModel.isNumber && value !== undefined) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            var decimalSeparator = colModel.formatoptions.decimalSeparator;
                            sanitizedValue = value.replaceAll(thousandsSeparator, "");
                            sanitizedValue = sanitizedValue.replaceAll(decimalSeparator, '.');
                        }

                        if (colModel.isInteger && value !== undefined) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            sanitizedValue = value.replaceAll(thousandsSeparator, "");
                        }

                        //TODO :  raise event
                        var data = jqGrid.rowData(rowid);
                        var eventArgs = {
                            cellName: cellname,
                            cellValue: sanitizedValue,
                            rowData: data
                        };
                        //raise event to enable listeners to inspect and/or to change the value entered by the user
                        onCellUpdating(eventArgs);

                        //check if the eventArgs object has been changed by listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.beforeSaveCell",
                                message: "eventArgs object corrupted by listener onCellUpdating"
                            });
                            return sanitizedValue;
                        }

                        if (isNotString(eventArgs.cellValue)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.beforeSaveCell",
                                message: "eventArgs.cellValue object corrupted by listener : '" + eventArgs.cellValue + "'",
                                info: "listeners on onCellUpdating should return a String type for the eventArgs.cellValue property"
                            });
                            return sanitizedValue;
                        }

                        // take value given by listeners
                        sanitizedValue = eventArgs.cellValue;


                        //if cell is a select element then we must revert the value back to the display value
                        if (colModel.isSelect) {
                            return null;
                        }

                        return sanitizedValue;

                    } catch (e) {
                        vpGrid.logException(e);
                        return value;
                    }
                }

                jqGrid.options.afterSaveCell = function (rowid, cellname, value, iRow, iCol) {
                    try {
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.afterSaveCell",
                                message: "ColModels not found : rowid='" + rowid + "'" + "; cellName='" + cellname + "'"
                            });
                            return;
                        }

                        var colModel = colModels[iCol];
                        if (isNullOrUndefinedOrEmpty(colModel)) {
                            vpGrid.logError({
                                message: "ColModel not found :  rowid='" + rowid + "'" + "; cellName='" + cellname + "'" + "; iCol='" + iCol + "'"
                            });
                            return;
                        }

                        var jqCell = jqGrid.cell(rowid, cellname);
                        //revert back overflow when colModel is Note

                        if (colModel.isNote) {
                            jqCell.css('overflow', '');
                        }

                        //update ui-state-error when there is a min/max limitation for value
                        if (jqGrid.cellValueIsInRange(rowid, cellname, value, colModel)) {
                            jqCell.removeClass('ui-state-error');
                        }

                        //update the filter toolbar with this new value
                        jqGrid.updateSearchInputDataSourceForCol(cellname, value);

                        // raise event onCellUpdated to enable listeners to do additional processing when cell content has been updated
                        // for example : change other cells based on business rules
                        var data = jqGrid.rowData(rowid);
                        var rowDataBefore = jqGrid.rowData(rowid);

                        var eventArgs = {
                            cellName: cellname,
                            cellValue: value,
                            rowid : rowid,
                            rowData: data
                        };

                        //raise event 
                        onCellUpdated(eventArgs);

                        //update columns that have been changed by the listener
                        var rowDataAfter = eventArgs.rowData;
                        jqGrid.options.updateRow(rowid, cellname,iRow, rowDataBefore, rowDataAfter);

                        var mustRefilterTheGrid = false;
                        if (jqGrid.userIsFilteringTheGridOnCol(cellname)) {
                            mustRefilterTheGrid = true;
                        }

                        if (mustRefilterTheGrid === true) {
                            //execute async to free the UI thread
                            vpGrid.showUINotificationAtElement(jqCell[0], "", vpGrid.UIString.rowWillDisappearDueToGridFiltering, {
                                hide: {
                                    event: false,
                                    inactive: 3000
                                }
                            });
                            executeAsync(this, function () {
                                try {
                                    jqGrid.filterGridFromSearchToolbar();

                                } catch (e) {
                                    vpGrid.logException(e);
                                }

                            }, 3000, "filterGrid");
                            
                        }

                        var gridHasRemoteFilterThatTargetsCol = jqGrid.hasRemoteFilterThatTargetsCol(cellname);
                        if (mustRefilterTheGrid === false && gridHasRemoteFilterThatTargetsCol === true) {
                            //user has changed a cell in a column that is targeted by a remote filter
                            vpGrid.showUINotificationAtElement(jqCell[0], "", vpGrid.UIString.rowWillDisappearDueToGridFiltering, {
                                hide: {
                                    event: false,
                                    inactive: 3000
                                }
                            });
                            var jqRow = jqGrid.row(rowid);
                            jqRow.attr(vpGrid.HtmlDataTag.RowMustBeRemoved, "true");
                            executeAsync(this, function () {
                                try {
                                    var jqRow = jqGrid.row(rowid);
                                    jqRow.addClass('vpgrid-hidden');
                                    //jqRow.hide();

                                    //reset the current selected row
                                    if (rowid === jqGrid.currentRowId) {
                                        jqGrid.currentRowId = null;
                                        jqGrid.lastSelectedCheckboxId = "";
                                        jqGrid.currentSelectedCheckboxId = "";
                                    }

                                    //Delete inline summary rows if any
                                    jqGrid.deleteInlineSummaryRowsForRow(rowid);

                                    //process summary rows if needed
                                    jqGrid.options.renderSummaryRows();

                                } catch (e) {
                                    vpGrid.logException(e);
                                }

                            }, 3000, "hideRow");
                        }

                        //update internal CRUD arrays 
                        jqGrid.updateDataWithUpdatedRow(rowDataAfter);

                        //update data on remote server when online
                        if (vpGrid.options.enableAutomaticPropagationOfUpdateInsertDeleteOperations === true) {
                            // grid is online
                            var jqCell = jqGrid.cell(rowid, cellname);
                            jqCell.addClass('vpgrid-refresh');
                            jqGrid.updateInsertDeleteDataOnRemote();
                        }

                        if (mustRefilterTheGrid === true) {
                            //do not call renderInlineSummaryRowsForRow and renderSummaryRowsCell
                            // because it will be called by the method that filters the grid
                            return;
                        }

                        if (gridHasRemoteFilterThatTargetsCol === true) {
                            
                            return;
                        }

                        //TODO : execute Async 
                        //TODO : factorize the call of both lines into one method (this code is duplicated at 3 places)
                        //process inline summary rows if needed
                        jqGrid.options.renderInlineSummaryRowsForRow(rowid);

                        //process summary rows if needed
                        jqGrid.options.renderSummaryRowsCell(colModel, true);

                            
                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.updateRow = function (rowid, cellname, iRow, rowDataBefore, rowDataAfter) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to update any adjacent cells in row after one cell in this row has been edited</summary>
                    /// <param name="rowid" type="String">The id of the row</param>
                    /// <param name="cellname" type="String">Name of the cell that has been edited. If listener has changed again this cell, the new value for this cell is discarded to avoid loop.</param>
                    /// <param name="iRow" type="Number">The position of the row</param>
                    /// <param name="rowDataBefore" type="Object">Complete row data before the cell was edited</param>
                    /// <param name="rowDataAfter" type="Object">Complete row data after the cell has been edited and after listeners may have changed some cells. </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        // check if something has changed
                        if (areEquals(rowDataBefore, rowDataAfter)) {
                            return;
                        }

                        var rowHasChanged = false;
                        for (var p in rowDataBefore) {
                            if (rowDataBefore[p] === rowDataAfter[p]) {
                                continue;
                            }

                            // check the property exists in target object
                            if (rowDataAfter[p] === undefined) {
                                continue;
                            }

                            // do not update again the cell
                            if (p === cellname) {
                                continue;
                            }

                            //check if the property is a column name
                            if (jqGrid.colDoesNotExist(p)) {
                                //TODO : log
                                continue;
                            }

                            //check if the cell is the key
                            // -> a key must never be changed
                            var colModel = jqGrid.colModelOf(p);
                            if (colModel.isKey) {
                                vpGrid.logError({
                                    functionName: "jqGrid.options.updateRow",
                                    message: "Cell value has been modified but is defined as primary key. Cell name : '" + p + "' , rowid : '" + rowid + "'",
                                    info: "Check the column schema in your Web Page. Check for the data attribute data-vpgrid-column-type=key"
                                })
                                continue;
                            }
                            
                            //update the cell
                            var newValue = rowDataAfter[p];
                            jqGrid.setCell(rowid, p, newValue);
                            rowHasChanged = true;

                        } // end for (var p in rowDataBefore)


                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.updateRowWithFormData = function (formData) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to update the row after a UI dialog has been submitted by the user.</summary>
                    /// <param name="formData" type="Object">Literal object that contains the values entered/modified by the user.
                    ///                                      Each property in this object must match the name of a column.
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(formData)) {
                            vpGrid.logError({
                                functionName: "updateRowWithFormData",
                                message: "Input form data is null or empty : '" + formData + "'"
                            });
                            return;
                        }

                        // get the html id of the row to be updated
                        //check if a key has been setup on the Key column
                        var keyColumnName = JQGrid.keyColumnName();
                        if (isNullOrUndefinedOrEmpty(keyColumnName)) {
                            vpGrid.logError({
                                functionName: "updateRowWithFormData",
                                message: "Key column not found.",
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnType + "=key'," + " must be defined int the column schema."
                            });
                            return;
                        }

                        var itemKey = formData[keyColumnName];
                        if (isNullOrUndefinedOrEmpty(itemKey)) {
                            vpGrid.logError({
                                functionName: "updateRowWithFormData",
                                message: "Input form data does not contain a property called : '" + keyColumnName + "'"
                            });
                            return;
                        }

                        if (isNotString(itemKey)) {
                            vpGrid.logError({
                                functionName: "updateRowWithFormData",
                                message: "Input form data property called : '" + keyColumnName + "' must be a string property. Its value is ':" + itemKey + "'"
                            });
                            return;
                        }

                        var jqRow = jqGrid.getRowThatHoldsItemWithKey(itemKey);
                        if (jqRow.notFound()) {
                            vpGrid.logError({
                                functionName: "updateRowWithFormData",
                                message: "Cannot find the htlm table row for the item with key ':" + itemKey + "'"
                            });
                            return;
                        }

                        var rowid = jqRow[0].id;
                        var rowDataBefore = jqGrid.rowData(rowid);
                        var rowDataAfter = $.extend({}, rowDataBefore, formData);
                        
                        // check if something has changed
                        if (areEquals(rowDataBefore, rowDataAfter)) {
                            return;
                        }

                        var rowHasChanged = false;
                        for (var p in rowDataBefore) {
                            if (rowDataBefore[p] === rowDataAfter[p]) {
                                continue;
                            }

                            // check the property exists in target object
                            if (rowDataAfter[p] === undefined) {
                                continue;
                            }

                            //check if the property is a column name
                            if (jqGrid.colDoesNotExist(p)) {
                                //TODO : log
                                continue;
                            }

                            //check if the cell is the key
                            // -> a key must never be changed
                            var colModel = jqGrid.colModelOf(p);
                            if (colModel.isKey) {
                                continue;
                            }

                            //update the cell
                            var newValue = rowDataAfter[p];
                            jqGrid.setCell(rowid, p, newValue);
                            rowHasChanged = true;

                            if (vpGrid.options.enableAutomaticPropagationOfUpdateInsertDeleteOperations === true) {
                                var jqCell = jqGrid.cell(rowid, p);
                                jqCell.addClass('vpgrid-refresh');
                            }

                            //update the search input box autocomplete
                            jqGrid.updateSearchInputDataSourceForCol(p,newValue);

                            //update the summary cell
                            //TODO : update summary cell -> see afterSaveCell function
                            //process inline summary rows if needed
                            jqGrid.options.renderInlineSummaryRowsForRow(rowid);

                            //process summary rows if needed
                            jqGrid.options.renderSummaryRowsCell(colModel, true);
                        }


                        if (rowHasChanged === false) {
                            return;
                        }

                        //update internal CRUD arrays 
                        jqGrid.updateDataWithUpdatedRow(rowDataAfter);

                        if (vpGrid.options.enableAutomaticPropagationOfUpdateInsertDeleteOperations === true) {
                            // grid is online
                            jqGrid.updateInsertDeleteDataOnRemote();
                            return;
                        }
                        
                        

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.updateRowWithResponseData = function (responseData) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to update the row after an insert/update operation has been triggered on server-side and upon reception of the server response.</summary>
                    /// <param name="responseData" type="Object">Literal object sent back by the server after the insert or update operation. 
                    ///             The data sent back by the server might contain modified columns (for example a column that is calculated on server side)
                    ///             Each property in this object must match the name of a column.
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(responseData)) {
                            vpGrid.logError({
                                functionName: "updateRowWithResponseData",
                                message: "Response data is null or empty : '" + responseData + "'"
                            });
                            return;
                        }

                        // get the html id of the row to be updated
                        //check if a key has been setup on the Key column
                        var keyColumnName = JQGrid.keyColumnName();
                        if (isNullOrUndefinedOrEmpty(keyColumnName)) {
                            vpGrid.logError({
                                functionName: "updateRowWithResponseData",
                                message: "Key column not found.",
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnType + "=key'," + " must be defined in the column schema."
                            });
                            return;
                        }

                        var itemKey = responseData[keyColumnName];
                        if (isNullOrUndefinedOrEmpty(itemKey)) {
                            vpGrid.logError({
                                functionName: "updateRowWithResponseData",
                                message: "Response data does not contain a property called : '" + keyColumnName + "'"
                            });
                            return;
                        }

                        if (isNotString(itemKey)) {
                            vpGrid.logError({
                                functionName: "updateRowWithResponseData",
                                message: "Response data property called : '" + keyColumnName + "' must be a string property. Its value is: '" + itemKey + "'"
                            });
                            return;
                        }

                        var jqRow = jqGrid.getRowThatHoldsItemWithKey(itemKey);
                        if (jqRow.notFound()) {
                            vpGrid.logError({
                                functionName: "updateRowWithResponseData",
                                message: "Cannot find the htlm table row for the item with key: '" + itemKey + "'"
                            });
                            return;
                        }

                        var rowid = jqRow[0].id;
                        var rowDataBefore = jqGrid.rowData(rowid);


                        //check if the row must be removed from the UI
                        var rowMustBeRemoved = jqRow.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.RowMustBeRemoved,false)
                        if (rowMustBeRemoved === true) {
                            jqGrid.removeRow(rowid);
                            jqGrid.options.gridComplete();
                            return;
                        }

                        var rowHasChanged = false;
                        var mustRefilterTheGrid = false;
                        for (var p in responseData) {
                            // check the property exists in the row data object
                            if (rowDataBefore[p] === undefined) {
                                continue;
                            }

                            //check if the server has changed the column value
                            if (rowDataBefore[p] === responseData[p]) {
                                continue;
                            }

                            //check if the property is a column name (should always be the case... until when?)
                            if (jqGrid.colDoesNotExist(p)) {
                                //TODO : log
                                continue;
                            }

                            //check if the cell is the key
                            // -> a key must never be changed
                            var colModel = jqGrid.colModelOf(p);
                            if (colModel.isKey) {
                                continue;
                            }

                            //update the cell
                            var newValue = responseData[p];

                            if (newValue === false) {
                                //hack to prevent jquery replace content with blank instead of the string false
                                // $(selector).html(false) -> inserts blank but should insert "false"
                                // $(selector).html(true) -> inserts "true" (and not blank)
                                newValue = "false";
                            }

                            jqGrid.setCell(rowid, p, newValue);
                            rowHasChanged = true;

                            if (jqGrid.userIsFilteringTheGridOnCol(p)) {
                                mustRefilterTheGrid = true;
                            }

                        } // end for (var p in responseData) {
                        if (mustRefilterTheGrid === true) {
                            //execute async to free the UI thread
                            executeAsync(jqRow[0], function () {
                                try {
                                    jqGrid.filterGridFromSearchToolbar();
                                } catch (e) {
                                    vpGrid.logException(e);
                                }

                            }, 100,"filterGrid");
                            return;
                        }
                        if (rowHasChanged === true) {
                            //update the summary cell
                            //TODO : update summary cell -> see afterSaveCell function
                            //process inline summary rows if needed
                            //execute async to free the UI thread
                            executeAsync(jqRow[0], function () {
                                try {
                                    jqGrid.options.renderInlineSummaryRowsForRow(rowid);

                                    //process summary rows if needed
                                    jqGrid.options.renderSummaryRowsCell(colModel, true);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }

                            }, 100);

                        }

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }




                jqGrid.options.afterUpdateInlineSummaryRow = function (rowid, summaryRowid, rowData) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to update cells styling  in an inline summary row after values in this inline row have been modified</summary>
                    /// <param name="rowid" type="String">The id of the row that is linked to the inline summary row.</param>
                    /// <param name="summaryRowid" type="String">The id of the inline summary row</param>
                    /// <param name="rowData" type="Object">Complete row data that was used to update the inline summary row</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        
                        if (isNullOrUndefinedOrEmpty(rowData)) {
                            //TODO : log
                            return;
                        }

                        for (var p in rowData) {
                            if (p.isNotCustomPropertyOf(rowData)) {
                                continue;
                            }
                            var colModel = jqGrid.colModelOf(p);

                            if (isNullOrUndefinedOrEmpty(colModel)) {
                                vpGrid.logError({
                                    message: "Column model not found for column named : '" + p + "'",
                                    functionName: "afterUpdateInlineSummaryRow",
                                    info: "The property '" + p + "' of input parameter rowData is ignored."

                                });
                                continue;
                            }

                            var cellValue = rowData[p];
                            var cellName = colModel.name;

                            //update ui-state-error when there is a min/max limitation for value
                            if (jqGrid.cellValueIsInRange(summaryRowid, cellName, cellValue, colModel)) {
                                var jqCell = jqGrid.inlineSummaryCell(summaryRowid, cellName);
                                jqCell.removeClass('ui-state-error');
                                continue;
                            }

                            if (jqGrid.cellValueIsOutOfRange(summaryRowid, cellName, cellValue, colModel)) {
                                var jqCell = jqGrid.inlineSummaryCell(summaryRowid, cellName);
                                jqCell.addClass('ui-state-error');
                                continue;
                            }
                            

                        }


                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                vpGrid.callToGridComplete = 0;
                vpGrid.callToGridCompleteAfterDebounce = 0;

                jqGrid.options.gridComplete = function () {
                    try {
                        vpGrid.callToGridComplete += 1;
                        //debounce the execution of gridComplete
                        executeAsync(this, function () {
                            try {
                                vpGrid.callToGridCompleteAfterDebounce += 1;
                                jqGrid.isReady = true;
                                updateFilteredItemCount();

                                executeAsync(this, updateContentPlaceholders, 50, "updateContentPlaceholders");
                                executeAsync(this, ensureOnlyOneRowCanBeChecked, 100, "ensureOnlyOneRowCanBeChecked");
                                
                                executeAsync(this, jqGrid.options.renderInlineSummaryRows, 200, "renderInlineSummaryRows");
                                executeAsync(this, jqGrid.initActivateDeactivateRibbonContent, 500, "initActivateDeactivateRibbonContent");
                                executeAsync(this, jqGrid.autoInsertNewLineAtBottom, 1000, "autoInsertNewLineAtBottom");

                                showOrHideEmptyMessageOnGridComplete();
                                

                            } catch (e) {
                                vpGrid.logException(e);
                            }


                        }, 500, "gridComplete");

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.options.loadComplete = function (data) {
                    /// <signature>
                    /// <summary>jqGrid extension. This method is called when jqGrid has filled the grid with input data 
                    ///                 be it the first load or be it after filtering through the search toolbar
                    /// </summary>
                    /// <param name="data" type="Object">Literal object passed by jqGrid.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (jqGrid.hasReceivedDataFromRemote === false) {
                            return;
                        }

                        var rows = data.rows;

                        if (isNotArray(rows)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.loadComplete",
                                message: "input data.rows is not an array."
                            });
                            return;
                        }

                        jqGrid.filteredData = rows;

                        var itemsCount = rows.length;
                        
                        //if (itemsCount === 0) {
                        //    return;
                        //}


                        // filter the data source of search input filters
                        executeAsync(rows, function () {
                            jqGrid.updateSearchInputDataSourcesWithFilteredDataRows(this);
                        }, 0, "updateSearchInputDataSourcesWithFilteredDataRows");

                        
                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.toDate = function (input) {
                    /// <signature>
                    /// <summary>Convert input string into a Date object
                    /// </summary>
                    /// <param name="input" type="String">input date formatted as string</param>
                    /// <returns type="Date">Returns the converted string as a Date object. 
                    ///             If conversion fails this method returns null</returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            return null;
                        }

                        if (isNotString(input)) {
                            vpGrid.logError({
                                functionName: "jqGrid.toDate",
                                message: "input value is not a string but is : " + typeof input
                            });
                            return null;
                        }

                        if (input.isNullOrEmptyOrWhitespace()) {
                            return null;
                        }

                        var dateFormat = vpGrid.options.datepickerOptions.dateFormat;
                        if ($.datepicker === undefined) {
                            vpGrid.logError({
                                functionName: "jqGrid.toDate",
                                message: "Cannot find datepicker plugin",
                                info: "Check that datepicker is included in the jQuery-UI library"
                            });
                            return null;
                        }

                        //parseDate may raise exception : see http://api.jqueryui.com/datepicker/
                        try {
                            var date = $.datepicker.parseDate(dateFormat, input);
                            return date;
                        } catch (e) {
                            return e.toString();
                        }
                        
                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.toNativeValues = function (input) {
                    /// <signature>
                    /// <summary>Convert input literal object 
                    ///     into another literal object where each property value (generally a string) is converted 
                    ///     to a type derived from the type of the corresponding column.
                    /// </summary>
                    /// <param name="input" type="Object">Literal object representing a data row : {col1:xxx, col2:yyy, ... colN:zzz}</param>
                    /// <returns type="Object">Returns a new literal object with same properties where values are converted from string to the native type of the column.
                    ///             If conversion fails the original property value is returned</returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            return null;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: 'jqGrid.toNativeValues',
                                message: "ColModels not found."
                            });
                            return input;
                        }

                        var nativeData = $.extend({}, input);
                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var colName = colModel.name;

                            if (nativeData[colName] === undefined) {
                                continue;
                            }

                            if (nativeData[colName] === null) {
                                continue;
                            }

                            var originalValue = nativeData[colName];
                            var sanitizedValue = jqGrid.unformatThisValueWithCol(originalValue,colName);

                            if (colModel.isCurrency) {
                                nativeData[colName] = sanitizedValue.toFloat();
                                continue;
                            }
                            if (colModel.isInteger) {
                                nativeData[colName] = sanitizedValue.toInt();
                                continue;
                            }

                            if (colModel.isNumber) {
                                nativeData[colName] = sanitizedValue.toFloat();
                                continue;
                            }

                            if (colModel.isDate) {
                                nativeData[colName] = jqGrid.toDate(sanitizedValue);
                            }

                        }
                        
                        return nativeData;

                    } catch (e) {
                        vpGrid.logException(e);
                        return input;
                    }
                }



                jqGrid.options.afterValidateCell = function (value, colTitle, iCol, dataRow) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners do custom validation. This method is called when jqGrid has done its own cell validation</summary>
                    /// <param name="value" type="String">Value of the cell being edited by the user</param>
                    /// <param name="colTitle" type="String">Title of the column's cell</param>
                    /// <param name="iCol" type="Number">Index of the column in the colmodels</param>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.
                    ///                                     dataRow is always undefined unless this method is call from the method jqGrid.validateDataRow()
                    ///                                     When dataRow is a valid object it is passed to the onCellValidating event handlers instead of the currently selected row in the grid.
                    /// </param>
                    /// <returns type="Array">Returns an array of values :first value - true or false. The value of true mean that the checking is successful false otherwise; the second value have sense only, if the first value is false, represents the error message which will be displayed to the user. Typically this can look like this [false,”Please enter valid value”]</returns>
                    /// </signature>
                    try {
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : afterValidateCell is stopped. colTitle='" + colTitle + "'"
                            });
                            return;
                        }

                        var colModel = colModels[iCol];
                        var cellName = colModel.name;

                        var data = null;

                        var rowid = jqGrid.currentRowId;
                        if (isNotNullOrUndefinedOrEmpty(rowid)) {
                            data = jqGrid.rowData(rowid);
                        }

                        if (dataRow !== undefined) {
                            data = dataRow;
                        }

                        //TODO : check if a modal dialog box is currently opened
                        //          -> if yes : build data object from the FORM input fields of the opened dialog

                        if (isNotString(value)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.afterValidateCell",
                                message: "input value is not a string but is : " + typeof value,
                                info : "input value is implicitly converted to string"
                            });
                            value = value + '';
                        }

                        var sanitizedValue = value;
                        var nativeValue = value;

                        if (colModel.isCurrency) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            var decimalSeparator = colModel.formatoptions.decimalSeparator;
                            sanitizedValue = value.replaceAll(thousandsSeparator, "");
                            sanitizedValue = sanitizedValue.replaceAll(decimalSeparator, '.');
                            nativeValue = sanitizedValue.toFloat();
                        }

                        if (colModel.isNumber) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            var decimalSeparator = colModel.formatoptions.decimalSeparator;
                            sanitizedValue = value.replaceAll(thousandsSeparator, "");
                            sanitizedValue = sanitizedValue.replaceAll(decimalSeparator, '.');
                            nativeValue = sanitizedValue.toFloat();
                        }

                        if (colModel.isInteger) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            sanitizedValue = value.replaceAll(thousandsSeparator, "");
                            nativeValue = sanitizedValue.toInt();
                        }

                        if (colModel.isDate) {
                            nativeValue = jqGrid.toDate(value);
                        }

                        var eventArgs = {
                            cellName: cellName,
                            cellValue: sanitizedValue,
                            cellNativeValue : nativeValue,
                            rowData: data,
                            isValid: true,
                            errorMessage: ""
                        };

                        //check if this event is raised within the context of a jQuery-UI Dialog
                        var currentDialog = vpGrid.currentUIModalDialog();
                        if (currentDialog !== null) {
                            eventArgs.dialogData = vpGrid.currentUIModalDialogData();
                            eventArgs.dialogId = vpGrid.currentUIModalDialogId();
                        }

                        //check if remote validation is setup
                        if (colModel.hasRemoteValidator === true ) {
                            onCellValidatingByRemote(eventArgs, colModel.editrules.remoteValidationUrl)
                        }

                        //raise event
                        onCellValidating(eventArgs);

                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.afterValidateCell",
                                message: "eventArgs object corrupted by listener"
                            });
                            return [true, "", ""];
                        }

                        if (isNotBoolean(eventArgs.isValid)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.afterValidateCell",
                                message: "eventArgs.isValid property corrupted by listener"
                            });
                            return [true, "", ""];;
                        }

                        if (eventArgs.isValid) {
                            return [true, "", ""];
                        }

                        return [false, eventArgs.errorMessage, ""];

                    } catch (e) {
                        vpGrid.logException(e);
                        //fallback to a successfull validation to prevent user being locked inside a cell
                        return [true, "", ""];
                    }
                }

                jqGrid.options.bindAutocompleteCell = function (rowid, input, value, cellName, iRow, iCol) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners configure autocomplete. 
                    ///     This method is called when jqGrid is in cell editing mode
                    /// </summary>
                    /// <param name="rowid" type="String">The id of the HTML table row</param>
                    /// <param name="input" type="Object">The input DOM element</param>
                    /// <param name="value" type="String">Value of the cell being edited by the user</param>
                    /// <param name="cellname" type="String">Cell name</param>
                    /// <param name="iCol" type="Number">Index of the column in the colmodels</param>
                    /// <returns type="Array">Returns an array of values :first value - true or false. The value of true mean that the checking is successful false otherwise; the second value have sense only, if the first value is false, represents the error message which will be displayed to the user. Typically this can look like this [false,”Please enter valid value”]</returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var rowData = jqGrid.rowData(rowid);

                        var eventArgs = {
                            cellName: cellName,
                            cellValue: value,
                            options: {},
                            data: [],
                            rowData: rowData
                        };

                        //raise event
                        onAutocompleteCellRendering(eventArgs);

                        if (isNullOrUndefinedOrEmpty(eventArgs.data)) {
                            eventArgs.data = jqGrid.colValues(cellName);
                        }

                        //TODO : serialize the options object to a data attribute on input element
                        bindAutoCompleteWidgetWithDataOnElement(input, eventArgs.data);

                        // bind to select event to automatically save the cell when an item is selected in the autocomplete list
                        jqInput.on("autocompleteselect", function (event, ui) {
                            try {
                                executeAsync(this,function () {
                                    try {
                                        jqGrid.saveCell(iRow, iCol);
                                    } catch (e) {
                                        vpGrid.logException(e);
                                    }
                                }, 50);


                            } catch (e) {
                                vpGrid.logException(e);
                            }

                        });

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.renderSummaryCell = function (summaryRow,colModel,updateOtherSummaryCells) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners inject custom content in a summary cell.</summary>
                    /// <param name="summaryRow" type="Object">The table row DOM element that holds the summary row.</param>
                    /// <param name="colModel" type="Object">The column model schema of the column where the summary cell is.</param>
                    /// <param name="updateOtherSummaryCells" type="Boolean">If set to true, a call to method renderMandatorySummaryCells will be done. </param>
                    /// </signature>
                    try {
                        if (jqGrid.options.footerrow === false) {
                            // there is no summary row
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(colModel)) {
                            vpGrid.logError({
                                message: "Cannot render summary cell. colModel object is null or empty."
                            });
                            return;
                        }

                        var cellName = colModel.name;

                        //find UI Identifier
                        var jqSummaryRow = $(summaryRow);
                        var uiIdentifier = jqSummaryRow.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIIdentifier,"")

                        

                        var eventArgs = {
                            cellName: cellName,
                            cellValue: "",
                            uiIdentifier : uiIdentifier,
                            useCellFormatter: false,
                            td: {},
                            remove: {},
                            isAsync: true
                        };

                        eventArgs.asyncInit = function () {
                            try {
                                //set visual clue that cell is computing
                                var jqCell = jqGrid.summaryCell(uiIdentifier, cellName);
                                jqCell.addClass('vpgrid-refresh');
                            } catch (e) {
                                vpGrid.logException(e);
                            }

                        };

                        eventArgs.asyncEnd = function () {
                            try {
                                //render summary cell
                                var jqGridHost = jqGrid.host();
                                var userData = {};
                                userData[cellName] = eventArgs.cellValue;
                                var useCellFormatter = eventArgs.useCellFormatter;

                                jqGrid.setFooterData(uiIdentifier, userData, useCellFormatter);

                                //jqGridHost.jqGrid("footerData", "set", userData, useCellFormatter);

                                var jqCell = jqGrid.summaryCell(uiIdentifier, cellName);

                                if (jqCell.notFound()) {
                                    vpGrid.logError({
                                        message: "Cannot style summary cell. Summary cell not found for column : '" + cellName + "'."
                                    });
                                    return;
                                }

                                //first remove classes:
                                if (isString(eventArgs.remove['class'])) {
                                    var cssClassToBeRemoved = eventArgs.remove['class'];
                                    jqCell.removeClass(cssClassToBeRemoved);
                                }

                                //TODO : remove other found attributes
                                jqCell.removeClass('vpgrid-refresh');

                                if (isString(eventArgs.td.title)) {
                                    jqCell.attr('title', eventArgs.td.title.toEncodedHTML());

                                }

                                if (isString(eventArgs.td['class'])) {
                                    jqCell.addClass(eventArgs.td['class']);
                                }

                                //if (isString(eventArgs.td.style)) {
                                //    htmlAttributes += (' style="' + eventArgs.td.style + '"');
                                //}

                                //TODO : check if listeners have injected other html attributes

                                if (updateOtherSummaryCells) {
                                    jqGrid.options.renderMandatorySummaryCells(summaryRow, cellName);
                                }
                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        };// end eventArgs.asyncCallback


                        //raise event to enable listeners set value and attributes on the summary <td> element
                        onSummaryCellRendering(eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                jqGrid.options.renderSummaryRow = function (element) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners do custom rendering of a summary row. This method is called when jqGrid is loading or sorting data</summary>
                    /// <param name="element" type="Object">the table row DOM element that holds the summary row.</param>
                    /// </signature>
                    try {

                        if (jqGrid.options.footerrow === false) {
                            // there is no summary row
                            return;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : renderSummaryRow is stopped."
                            });
                            return;
                        }
                        var colCount = colModels.length;
                        var rowCheckboxIsEnabled = jqGrid.options.multiselect;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var cellName = colModel.name;
                            if (colModel.hidden) {
                                continue;
                            }

                            if (cellName === "cb" && rowCheckboxIsEnabled) {
                                // no summary on checkbox row cell 
                                // continue;
                            }


                            //jqGrid.options.renderSummaryCell(element,colModel,false);

                            //execute async to free the UI thread
                            var context = { element: element, colModel: colModel };
                            executeAsync(context, function () {
                                try {
                                    jqGrid.options.renderSummaryCell(this.element, this.colModel, false);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }

                            }, 0);

                        }

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.renderMandatorySummaryCells = function (summaryRow, excludedCellName) {
                    /// <signature>
                    /// <summary>Let listeners inject custom content for all adjacent cells that need to computed in the summary row.</summary>
                    /// <param name="summaryRow" type="Object">The table row DOM element that holds the summary row.</param>
                    /// <param name="excludedCellName" type="Object">Name of the summary cell whose content has already been set by listeners.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.renderMandatorySummaryCells",
                                message: "ColModels not found."
                            });
                            return;
                        }

                        var colsCount = colModels.length;
                        for (var i = 0; i < colsCount; i++) {
                            var colModel = colModels[i];
                            if (colModel.name === excludedCellName) {
                                continue;
                            }

                            if (colModel.alwaysUpdateSummaryCell === true) {
                                // always call with false to prevent looping
                                jqGrid.options.renderSummaryCell(summaryRow,colModel, false);
                            }

                        }

                        
                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.renderSummaryRows = function () {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners do custom rendering of any summary row. 
                    ///     This method is called when jqGrid is loading or sorting data.
                    /// </summary>
                    /// </signature>
                    try {

                        if (jqGrid.options.footerrow === false) {
                            // there is no summary row
                            return;
                        }

                        var jqSummaryRows = jqGrid.summaryRows();
                        if (jqSummaryRows.notFound()) {
                            vpGrid.logError({
                                message: "Summary rows not found : renderSummaryRows is stopped."
                            });
                            return;
                        }

                        var summaryRowCount = jqSummaryRows.length;
                        
                        for (var i = 0; i < summaryRowCount; i++) {
                            var summaryRow = jqSummaryRows[i];

                            //execute async to free the UI thread
                            executeAsync(summaryRow, function () {
                                try {
                                    //jqGrid.options.renderSummaryRow(summaryRow);
                                    jqGrid.options.renderSummaryRow(this);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                                    
                            }, 0);
                            
                        }

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.renderSummaryRowsCell = function (colModel, updateOtherSummaryCells) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners inject custom content in a summary cell in all related summary rows.</summary>
                    /// <param name="colModel" type="Object">The column model schema of the column where the summary cell is.</param>
                    /// <param name="updateOtherSummaryCells" type="Boolean">If set to true, a call to method renderMandatorySummaryCells will be done. </param>
                    /// </signature>
                    try {
                        if (jqGrid.options.footerrow === false) {
                            // there is no summary row
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(colModel)) {
                            vpGrid.logError({
                                message: "Cannot render summary cell. colModel object is null or empty."
                            });
                            return;
                        }

                        var cellName = colModel.name;

                        var jqSummaryRows = jqGrid.summaryRows();
                        var summaryRowsCount = jqSummaryRows.length;
                        for (var i = 0; i < summaryRowsCount; i++) {
                            var summaryRow = jqSummaryRows[i];

                            //execute async to free the UI thread
                            var context = {
                                summaryRow : summaryRow,
                                colModel : colModel,
                                updateOtherSummaryCells : updateOtherSummaryCells
                            };
                            executeAsync(context, function () {
                                try {
                                    //jqGrid.options.renderSummaryCell(summaryRow, colModel, updateOtherSummaryCells);
                                    // within this execution block the this keyword represents the context object passed to the executeAsync method
                                    jqGrid.options.renderSummaryCell(this.summaryRow, this.colModel, this.updateOtherSummaryCells);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            }, 0);


                        } // end for (var i = 0; i < summaryRowsCount; i++) {


                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                jqGrid.options.renderInlineSummaryRows = function () {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners insert inline summary rows. This method is called when jqGrid is loaded or sorted data</summary>
                    /// </signature>
                    try {
                        if (vpGrid.options.enableInlineSummaryRows === false) {
                            return;
                        }

                        //get all rowids
                        var jqGridHost = jqGrid.host();

                        var inGridRowIds = jqGridHost.jqGrid("getDataIDs");
                        if (isNullOrUndefinedOrEmpty(inGridRowIds)) {
                            // nothing to do
                            return;
                        }

                        var rowsCount = inGridRowIds.length;
                        for (var i = 0; i < rowsCount; i++) {
                            var rowid = inGridRowIds[i];

                            //check if this row is an inline summary row
                            if (jqGrid.isInlineSummaryRow(rowid)) {
                                continue;
                            }

                            jqGrid.options.renderInlineSummaryRowsForRow(rowid);

                        }


                    } catch (e) {
                        vpGrid.logException(e);

                    }
                    finally {
                        executeAsync(this, jqGrid.options.renderSummaryRows, 1000, "renderSummaryRows");
                    }
                }

                jqGrid.options.renderInlineSummaryRowsForRow = function (rowid) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners insert/update inline summary rows. This method is called after a cell has been updated in row identified by rowid.</summary>
                    /// <param name="rowid" type="String">Dom id of the row. Each row in a grid may have between 0 and N inline summary row associated to it.</param>
                    /// </signature>
                    try {
                        if (vpGrid.options.enableInlineSummaryRows === false) {
                            return;
                        }

                        if (isNotString(rowid)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.renderInlineSummaryRowsForRow",
                                message: "rowid is not valid string :'" + rowid + "'"
                            });
                            return;
                        }

                        //TODO : check rowid is an existing row

                        var rowData = jqGrid.rowData(rowid);
                        var eventArgs = {
                            rowid: rowid,
                            rowData: rowData
                        };

                        //raise event
                        onInlineSummaryRowRendering(eventArgs);

                      

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.autoInsertNewLineAtBottom = function () {
                    /// <signature>
                    /// <summary>Automatically adds a new empty line at the bottom of the grid.
                    /// This new line is added only if : 
                    ///                 - jqGrid.options.autoInsertNewLineAtBottom = true
                    ///                 - there is no empty line already available at the bottom of the grid
                    ///                 - this feature ensure massive insertion and edition within the grid
                    ///</summary>
                    /// </signature>
                    try {
                        if (jqGrid.options.autoInsertNewLineAtBottom === false) {
                            return;
                        }

                        //check if row has already been inserted
                        if (jqGrid.hasNewRowInsertedAtBottom === true) {
                            return;
                        }

                        var emptyRowData = jqGrid.emptyRowData();
                        
                        //Do not swap these two lines, otherwise a loop will happen
                        jqGrid.hasNewRowInsertedAtBottom = true;
                        jqGrid.insertNewRow(emptyRowData, 'last');

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }



                jqGrid.restoreCell = function (iRow, iCol, rowid) {
                    /// <signature>
                    /// <summary> Restore the cell content for the cll located on column index iCol and row index iRow
                    /// </summary>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        var jqGridHost = jqGrid.host();
                        jqGridHost.jqGrid("restoreCell", iRow, iCol);

                        //restore overflow css property on note column
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: "jqGrid.restoreCell",
                                message: "ColModels not found : iRow='" + iRow + "'" + "; iCol='" + iCol + "'"
                            });
                            return;
                        }

                        var colModel = colModels[iCol];
                        if (isNullOrUndefinedOrEmpty(colModel)) {
                            vpGrid.logError({
                                functionName: "jqGrid.restoreCell",
                                message: "colModel not found : iRow='" + iRow + "'" + "; iCol='" + iCol + "'"
                            });
                            return;
                        }


                        //revert back overflow when colModel is Note
                        if (colModel.isNote) {
                            var jqCell = jqGrid.cell(rowid, colModel.name);
                            jqCell.css('overflow', '');
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                jqGrid.saveCell = function (iRow, iCol) {
                    try {
                        var jqGridHost = jqGrid.host();
                        jqGridHost.jqGrid("saveCell", iRow, iCol);
                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onCellValidating(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onCellValidating, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onDataRowValidating(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onDataRowValidating, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onCellValidatingByRemote(eventArgs, validationUrl) {
                    try {

                        //TODO : raise event
                        //EventHandlers.raiseEvent(vpGrid.Event.onCellValidatingByRemote, vpGrid, eventArgs);

                        //TODO : refactor the propagation of the query string to be done in only on place
                        //step1bis : gather all parameters from the Query String 
                        var dataFromQueryString = jqGrid.getQueryStringData();
                        extendOrMerge(eventArgs, dataFromQueryString);

                        var ajaxOptions = {
                            cache: false,
                            async : false,
                            type: "GET",
                            dataType: "json",
                            url: validationUrl,
                            data : eventArgs,
                            success: function (response) {
                                try {
                                    
                                    if (isNullOrUndefinedOrEmpty(response)) {
                                        eventArgs.isValid = false;
                                        eventArgs.errorMessage = vpGrid.UIString.serverResponseFormatIsNotValid;
                                        return;
                                    }

                                    if (isNullOrUndefinedOrEmpty(response.data)) {
                                        eventArgs.isValid = false;
                                        eventArgs.errorMessage = vpGrid.UIString.serverResponseFormatIsNotValid;
                                        return;
                                    }

                                    if (response.done === undefined) {
                                        eventArgs.isValid = false;
                                        eventArgs.errorMessage = vpGrid.UIString.serverResponseFormatIsNotValid;
                                        return;
                                    }

                                    if (response.done === false) {
                                        eventArgs.isValid = false;
                                        eventArgs.errorMessage = response.errorMessage;
                                        return;
                                    }

                                    eventArgs.isValid = response.data.isValid;
                                    eventArgs.errorMessage = response.data.errorMessage;


                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            },
                            complete: function (xhr, textStatus) {
                                try {
                                    
                                    if (xhr && xhr.status !== 200) {
                                        eventArgs.isValid = false;
                                        eventArgs.errorMessage = ajaxHttpStatusCodeInfo(xhr.status);
                                    }

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                                
                            }
                        };

                        $.extend(ajaxOptions, vpGridAjaxOptions);
                        $.ajax(ajaxOptions);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }


                function updateContentPlaceholders() {
                    try {
                        var jqGridContainer = jqGrid.container();
                        var elementsSelector = "[" + vpGrid.HtmlDataTag.UIContentPlaceholder + "=true]";
                        var jqElements = jqGridContainer.find(elementsSelector);
                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        // step 2 : take only elements that must be processed in this specific timeline sequence
                        var elementsCount = jqElements.length;
                        for (var i = 0; i < elementsCount; i++) {
                            var element = jqElements[i];

                            fillContentPlaceholderOnElement(element);
                        }
                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function updateFilteredItemCount() {
                    try {
                        //jqGrid.filteredItemCount is automatically updated by calling jqGrid.rows
                        var jqRows = jqGrid.rows();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.imageFormatter = function (cellValue, options, rowObject) {
                    try {
                        if (isNullOrUndefinedOrEmpty(cellValue)) {
                            cellValue = "";
                        }

                        var colModel = options.colModel;
                        var cellName = colModel.name;
                        var data = rowObject;

                        var eventArgs = {
                            cellName: cellName,
                            cellValue: cellValue,
                            rowData: data,
                            img: {
                                alt: cellValue,
                                title: cellValue,
                                src: ""
                            }
                        };

                        //raise event to enable listeners to inspect and/or to inject values for the attributes of image tag
                        onImageCellRendering(eventArgs);

                        //check if the src attribute has been setup
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "jqGrid.imageFormatter",
                                message: "eventArgs object corrupted by listener"
                            });
                            return "";
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.img)) {
                            vpGrid.logError({
                                functionName: "jqGrid.imageFormatter",
                                message: "eventArgs.img object corrupted by listener"
                            });
                            return "";
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.img.src)) {
                            return "";
                        }

                        //TODO : log if img.alt attribute has been changed

                        //render the img tag
                        var image = $("<img>", eventArgs.img);
                        var span = $('<span>');
                        var wrappedImage = image.appendTo(span);
                        return wrappedImage.parent().html();


                    } catch (e) {
                        vpGrid.logException(e);
                        return "";
                    }
                }

                jqGrid.imageUnformatter = function (cellValue, options, cell) {
                    try {
                        var jqCell = $(cell);
                        var jqImage = jqCell.find('img');
                        var altvalue = jqImage.toStringOrDefaultFromAttribute("alt", "");
                        return altvalue;

                    } catch (e) {
                        vpGrid.logException(e);
                        return cellValue;
                    }
                }

                jqGrid.linkFormatter = function (cellValue, options, rowObject) {
                    try {
                        if (isNullOrUndefinedOrEmpty(cellValue)) {
                            cellValue = "";
                        }

                        var colModel = options.colModel;
                        var cellName = colModel.name;

                        
                        var data = rowObject;

                        //check if rowObject is a DOM object
                        if ($(rowObject).is("tr")) {
                            //likformatter is called on a cell updating process (after the cell has been edited)
                            //rowObject represents the HTML TR on which the link must be rendered
                            data = jqGrid.rowData(rowObject.id);
                            //update the data object with the new cell value (the value entered by the user)
                            data[cellName] = cellValue;
                        }
                        
                        var target = "_vpTab";
                        var formatOptions = colModel.formatOptions || {};
                        if (isNotNullOrUndefinedOrEmpty(formatOptions.target)) {
                            target = formatOptions.target;
                        }

                        //extract link content
                        var linkContent = cellValue.leafName();

                        var eventArgs = {
                            cellName: cellName,
                            cellValue: cellValue,
                            rowData: data,
                            a: {
                                href: cellValue,
                                title: cellValue,
                                target: target
                            },
                            html: linkContent
                        };

                        //raise event to enable listeners to inspect and/or to inject values for the attributes of <a> tag
                        onLinkCellRendering(eventArgs);

                        //check if the src attribute has been setup
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "jqGrid.linkFormatter",
                                message: "eventArgs object corrupted by listener"
                            });
                            return "";
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.a)) {
                            vpGrid.logError({
                                functionName: "jqGrid.linkFormatter",
                                message: "eventArgs.a object corrupted by listener"
                            });
                            return "";
                        }

                        //TODO : log if a.href attribute has been changed

                        if (isNullOrUndefinedOrEmpty(eventArgs.a.href)) {
                            return "";
                        }

                        //TODO : log if eventArgs.html attribute has been changed
                        if (isNullOrUndefinedOrEmpty(eventArgs.html)) {
                            return "";
                        }

                        //render the a tag
                        var link = $("<a>", eventArgs.a);
                        link.attr("data-vpgrid-cell-value", cellValue);
                        link.html(eventArgs.html);
                        var span = $('<span>');
                        var wrappedLink = link.appendTo(span);
                        return wrappedLink.parent().html();

                    } catch (e) {
                        vpGrid.logException(e);
                        return "";
                    }
                }

                jqGrid.linkUnformatter = function (cellValue, options, cell) {
                    try {
                        var jqCell = $(cell);
                        var jqLink = jqCell.find('a');
                        var hrefValue = jqLink.toStringOrDefaultFromAttribute("href", "");
                        var originalCellValue = jqLink.toStringOrDefaultFromAttribute("data-vpgrid-cell-value", "");
                        if (isNotNullOrUndefinedOrEmpty(originalCellValue)) {
                            return originalCellValue;
                        }

                        return hrefValue;

                    } catch (e) {
                        vpGrid.logException(e);
                        return cellValue;
                    }
                }

                jqGrid.cannotDeleteItemFormatter = function (cellValue, options, rowObject) {
                    try {
                        if (isNullOrUndefinedOrEmpty(cellValue)) {
                            cellValue = "";
                        }
                        
                        var colModel = options.colModel;
                        var cellName = colModel.name;
                        var data = rowObject;

                        //render the cannot delete button
                        var divButton = $("<div>");
                        divButton.addClass("vpgrid-button-delete");
                        $("<span>").addClass("ui-icon ui-icon-link").appendTo(divButton);

                        var span = $('<span>');
                        var wrappedDiv = divButton.appendTo(span);
                        return wrappedDiv.parent().html();

                    } catch (e) {
                        vpGrid.logException(e);
                        return "";
                    }
                }

                jqGrid.deleteItemFormatter = function (cellValue, options, rowObject) {
                    try {
                        if (isNullOrUndefinedOrEmpty(cellValue)) {
                            cellValue = "";
                        }

                        var colModel = options.colModel;
                        var cellName = colModel.name;
                        var data = rowObject;

                        //check if the row is deletable
                        if (jqGrid.cannotDeleteDataRow(data)) {
                            return jqGrid.cannotDeleteItemFormatter(cellValue, options, rowObject);
                        }

                        //render the delete button
                        var divButton = $("<div>");
                        divButton.addClass("vpgrid-button-delete");
                        $("<span>").addClass("ui-icon ui-icon-trash").appendTo(divButton);
                        
                        var span = $('<span>');
                        var wrappedDiv = divButton.appendTo(span);
                        return wrappedDiv.parent().html();

                    } catch (e) {
                        vpGrid.logException(e);
                        return "";
                    }
                }

                jqGrid.deleteItemUnformatter = function (cellValue, options, cell) {
                    try {
                        var jqCell = $(cell);
                        return cellValue;

                    } catch (e) {
                        vpGrid.logException(e);
                        return cellValue;
                    }
                }

                function onCellRendering(eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onCellRendering, vpGrid, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onCellRendering",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.td)) {
                            eventArgs.td = eventArgsCopy.td;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onSummaryCellRendering(eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onSummaryCellRendering, vpGrid, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onSummaryCellRendering",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.td)) {
                            eventArgs.td = eventArgsCopy.td;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.remove)) {
                            eventArgs.remove = eventArgsCopy.remove;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.cellValue)) {
                            eventArgs.cellValue = "";
                        }

                        if (isNotBoolean(eventArgs.useCellFormatter)) {
                            eventArgs.useCellFormatter = false;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onImageCellRendering(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onImageCellRendering, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onLinkCellRendering(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onLinkCellRendering, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onAutocompleteCellRendering(eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onAutocompleteCellRendering, vpGrid, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onAutocompleteCellRendering",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.options)) {
                            eventArgs.options = eventArgsCopy.options;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.data)) {
                            eventArgs.data = eventArgsCopy.data;
                        }

                        if (isNotArray(eventArgs.data)) {
                            vpGrid.logError({
                                functionName: "onAutocompleteCellRendering",
                                message: "eventArgs.data array corrupted by listener",
                                info: "eventArgs.data is reverted to its original state"
                            });
                            eventArgs.data = eventArgsCopy.data;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onCellUpdating(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onCellUpdating, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onCellUpdated(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onCellUpdated, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onInlineSummaryRowRendering(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onInlineSummaryRowRendering, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onRowEditing(source, eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onRowEditing, source, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onRowEditing",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNotBoolean(eventArgs.cancel)) {
                            vpGrid.logError({
                                functionName: "onRowEditing",
                                message: "eventArgs.cancel property corrupted by listener",
                                info: "eventArgs.cancel value is reverted to its original state"
                            });
                            eventArgs.cancel = false;
                            return;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onCellEditing(source, eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onCellEditing, source, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onCellEditing",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNotBoolean(eventArgs.cancel)) {
                            vpGrid.logError({
                                functionName: "onCellEditing",
                                message: "eventArgs.cancel property corrupted by listener",
                                info: "eventArgs.cancel value is reverted to its original state"
                            });
                            eventArgs.cancel = false;
                            return;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }


                function onInsertingDataOnRemote(source, eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onInsertingDataOnRemote, source, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onInsertingDataOnRemote",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNotBoolean(eventArgs.cancel)) {
                            vpGrid.logError({
                                functionName: "onInsertingDataOnRemote",
                                message: "eventArgs.cancel property corrupted by listener",
                                info: "eventArgs.cancel value is reverted to its original state"
                            });
                            eventArgs.cancel = false;
                            return;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onUpdatingDataOnRemote(source, eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onUpdatingDataOnRemote, source, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onUpdatingDataOnRemote",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNotBoolean(eventArgs.cancel)) {
                            vpGrid.logError({
                                functionName: "onUpdatingDataOnRemote",
                                message: "eventArgs.cancel property corrupted by listener",
                                info: "eventArgs.cancel value is reverted to its original state"
                            });
                            eventArgs.cancel = false;
                            return;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onDeletingDataOnRemote(source, eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onDeletingDataOnRemote, source, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onDeletingDataOnRemote",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNotBoolean(eventArgs.cancel)) {
                            vpGrid.logError({
                                functionName: "onDeletingDataOnRemote",
                                message: "eventArgs.cancel property corrupted by listener",
                                info: "eventArgs.cancel value is reverted to its original state"
                            });
                            eventArgs.cancel = false;
                            return;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onDataInsertedUpdatedDeletedOnRemote(source,eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onDataInsertedUpdatedDeletedOnRemote, source, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }


                jqGrid.defaultCurrencyFormatOptions = function () {
                    try {

                        var formatOptions = $.jgrid.formatter.currency;
                        return formatOptions;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.defaultNumberFormatOptions = function () {
                    try {

                        var formatOptions = $.jgrid.formatter.number;
                        return formatOptions;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.defaultIntegerFormatOptions = function () {
                    try {

                        var formatOptions = $.jgrid.formatter.integer;
                        return formatOptions;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }


                jqGrid.defaultDateFormatOptions = function () {
                    try {

                        var formatOptions = $.jgrid.formatter.date;
                        return formatOptions;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }



                function bindEventsOnInputDateEditing(input,rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the input field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        //unbind events bound by jqGrid
                        jqInput.unbind("keydown");

                        // re-bind the keydown event with our implementation
                        //backup original value
                        var originalValue = jqInput.val();

                        jqInput.bind("keydown", function (e) {
                            try {
                                // case Escape
                                if (e.keyCode === 27) {
                                    //hide the datepicker
                                    hideWidgetOnElement(this);
                                    //jqGridHost.jqGrid("restoreCell", iRow, iCol);
                                    jqGridHost.jqGrid("setCell", rowid, iCol, originalValue, false, false, true);

                                    return false;
                                }

                                // case ENTER
                                if (e.keyCode === 13) {
                                    hideWidgetOnElement(this);
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);
                                    return false;
                                }

                                // case TAB
                                if (e.keyCode === 9) {
                                    //TODO : check if cell has been modified
                                    hideWidgetOnElement(this);
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);

                                    //case Shift TAB
                                    if (e.shiftKey) {
                                        jqGridHost.jqGrid("prevCell", iRow, iCol);
                                        return false;
                                    }

                                    jqGridHost.jqGrid("nextCell", iRow, iCol);
                                    return false;
                                }


                            } catch (ex) {
                                vpGrid.logException(ex);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function bindEventsOnSelectEditing(input,rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the select field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        //unbind events bound by jqGrid
                        jqInput.unbind("keydown");

                        // re-bind the keydown event with our implementation
                        jqInput.bind("keydown", function (e) {
                            try {
                                // case Escape
                                if (e.keyCode === 27) {
                                    jqGridHost.jqGrid("restoreCell", iRow, iCol);
                                    return false;
                                }

                                // case ENTER
                                if (e.keyCode === 13) {
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);
                                    return false;
                                }

                                // case TAB
                                if (e.keyCode === 9) {
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);
                                    //case Shift TAB
                                    if (e.shiftKey) {
                                        jqGridHost.jqGrid("prevCell", iRow, iCol);
                                        return false;
                                    }

                                    jqGridHost.jqGrid("nextCell", iRow, iCol);
                                    return false;
                                }

                                // case KeyUP
                                if (e.keyCode === 38) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    // we must prevent the onchange event in this case
                                    $(this).unbind('change');
                                    return true;
                                }

                                // case Key Down
                                if (e.keyCode === 40) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    // we must prevent the onchange event in this case
                                    $(this).unbind('change');
                                    return true;
                                }

                                // case left arrow
                                if (e.keyCode === 37) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    return false;
                                }

                                // case right arrow
                                if (e.keyCode === 39) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    return false;
                                }

                            } catch (ex) {
                                vpGrid.logException(ex);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });

                        jqInput.bind('blur', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);
                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                        //automaticall save the cell when an option has been selected in the Select element
                        jqInput.bind('change', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);

                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function bindEventsOnTextAreaEditing(input,rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the TextArea field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        //unbind events bound by jqGrid
                        jqInput.unbind("keydown");

                        // re-bind the keydown event with our implementation
                        jqInput.bind("keydown", function (e) {
                            try {
                                // case Escape
                                if (e.keyCode === 27) {
                                    //jqGridHost.jqGrid("restoreCell", iRow, iCol);
                                    jqGrid.restoreCell(iRow, iCol,rowid);
                                    return false;
                                }

                                // case ENTER
                                if (e.keyCode === 13) {
                                    //do nothing
                                    //jqGridHost.jqGrid("saveCell", iRow, iCol);
                                    return true;
                                }

                                // case TAB
                                if (e.keyCode === 9) {
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);
                                    //case Shift TAB
                                    if (e.shiftKey) {
                                        jqGridHost.jqGrid("prevCell", iRow, iCol);
                                        return false;
                                    }

                                    jqGridHost.jqGrid("nextCell", iRow, iCol);
                                    return false;
                                }


                                // case KeyUP
                                if (e.keyCode === 38) {
                                    // do nothing (user wants to navigate in the text with the up/dow key
                                    return true;
                                }

                                // case Key Down
                                if (e.keyCode === 40) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    return true;
                                }

                                // case left arrow
                                if (e.keyCode === 37) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    return true;
                                }

                                // case right arrow
                                if (e.keyCode === 39) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    return true;
                                }

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });

                        jqInput.bind('blur', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);
                                var context = {
                                    rowid: rowid,
                                    iCol : iCol
                                };
                                executeAsync(context, function () {
                                    try {
                                        var colModels = jqGrid.currentColModels();
                                        var colModel = colModels[context.iCol];
                                        var jqCell = jqGrid.cell(context.rowid, colModel.name);
                                        jqCell.css('overflow', '');
      
                                    } catch (e) {
                                        vpGrid.logException(e);
                                    }
                                }, 100);

                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });



                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function bindEventsOnCurrencyEditing(input,rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the input field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        jqInput.bind('blur', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);
                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                        jqInput.bind('focus', function () {
                            try {
                                
                                // Prevent default action
                                $(this).val($(this).val());
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });



                        //unbind events bound by jqGrid
                        jqInput.unbind("keypress");

                        // re-bind the keydown event with our implementation
                        jqInput.bind("keypress", function (e) {
                            try {

                                var keyCode = e.which;
                                
                                if (keyCode === 48) { //0
                                    return true;
                                }
                                if (keyCode === 49) { //1
                                    return true;
                                }
                                if (keyCode === 50) { //2
                                    return true;
                                }
                                if (keyCode === 51) { //3
                                    return true;
                                }
                                if (keyCode === 52) { //4
                                    return true;
                                }
                                if (keyCode === 53) { //5
                                    return true;
                                }
                                if (keyCode === 54) { //6
                                    return true;
                                }
                                if (keyCode === 55) { //7
                                    return true;
                                }
                                if (keyCode === 56) { //8
                                    return true;
                                }
                                if (keyCode === 57) { //9
                                    return true;
                                }
                                if (keyCode === 8) { //backspace
                                    return true;
                                }

                                if (keyCode === 32) { //space
                                    return true;
                                }

                                if (keyCode === 44) { //comma
                                    return true;
                                }

                                if (keyCode === 46) { //point
                                    return true;
                                }

                                if (keyCode === 45) { //-
                                    return true;
                                }

                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });




                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function bindEventsOnNumberEditing(input,rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the input field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        jqInput.bind('blur', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);
                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                        jqInput.bind('focus', function () {
                            try {

                                // Prevent default action
                                $(this).val($(this).val());
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });


                        //unbind events bound by jqGrid
                        jqInput.unbind("keypress");

                        // re-bind the keydown event with our implementation
                        jqInput.bind("keypress", function (e) {
                            try {

                                var keyCode = e.which;
                                if (keyCode === 48) { //0
                                    return true;
                                }
                                if (keyCode === 49) { //1
                                    return true;
                                }
                                if (keyCode === 50) { //2
                                    return true;
                                }
                                if (keyCode === 51) { //3
                                    return true;
                                }
                                if (keyCode === 52) { //4
                                    return true;
                                }
                                if (keyCode === 53) { //5
                                    return true;
                                }
                                if (keyCode === 54) { //6
                                    return true;
                                }
                                if (keyCode === 55) { //7
                                    return true;
                                }
                                if (keyCode === 56) { //8
                                    return true;
                                }
                                if (keyCode === 57) { //9
                                    return true;
                                }
                                if (keyCode === 8) { //backspace
                                    return true;
                                }

                                if (keyCode === 32) { //space
                                    return true;
                                }

                                if (keyCode === 44) { //comma
                                    return true;
                                }

                                if (keyCode === 46) { //point
                                    return true;
                                }

                                if (keyCode === 45) { //-
                                    return true;
                                }

                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function bindEventsOnIntegerEditing(input,rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the input field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        jqInput.bind('blur', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);
                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                        jqInput.bind('focus', function () {
                            try {

                                // Prevent default action
                                $(this).val($(this).val());
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });


                        //unbind events bound by jqGrid
                        jqInput.unbind("keypress");

                        // re-bind the keydown event with our implementation
                        jqInput.bind("keypress", function (e) {
                            try {

                                var keyCode = e.which;
                                if (keyCode === 48) { //0
                                    return true;
                                }
                                if (keyCode === 49) { //1
                                    return true;
                                }
                                if (keyCode === 50) { //2
                                    return true;
                                }
                                if (keyCode === 51) { //3
                                    return true;
                                }
                                if (keyCode === 52) { //4
                                    return true;
                                }
                                if (keyCode === 53) { //5
                                    return true;
                                }
                                if (keyCode === 54) { //6
                                    return true;
                                }
                                if (keyCode === 55) { //7
                                    return true;
                                }
                                if (keyCode === 56) { //8
                                    return true;
                                }
                                if (keyCode === 57) { //9
                                    return true;
                                }
                                if (keyCode === 8) { //backspace
                                    return true;
                                }
                                if (keyCode === 45) { //-
                                    return true;
                                }

                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function bindEventsOnInputEditing(input, rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the input field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        jqInput.bind('blur', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);
                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }




                function bindEventsOnInputAutocompleteEditing(input, rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the input field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        //unbind events bound by jqGrid
                        jqInput.unbind("keydown");

                        // re-bind the keydown event with our implementation
                        //backup original value
                        var originalValue = jqInput.val();

                        jqInput.bind("keydown", function (e) {
                            try {
                                // case Escape
                                if (e.keyCode === 27) {
                                    //hide the datepicker
                                    hideWidgetOnElement(this);
                                    //jqGridHost.jqGrid("restoreCell", iRow, iCol);
                                    jqGridHost.jqGrid("setCell", rowid, iCol, originalValue, false, false, true);

                                    return false;
                                }

                                // case ENTER
                                if (e.keyCode === 13) {
                                    hideWidgetOnElement(this);
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);
                                    return false;
                                }

                                // case TAB
                                if (e.keyCode === 9) {
                                    //TODO : check if cell has been modified
                                    hideWidgetOnElement(this);
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);

                                    //case Shift TAB
                                    if (e.shiftKey) {
                                        jqGridHost.jqGrid("prevCell", iRow, iCol);
                                        return false;
                                    }

                                    jqGridHost.jqGrid("nextCell", iRow, iCol);
                                    return false;
                                }


                            } catch (ex) {
                                vpGrid.logException(ex);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }





                function onSelectCellRendering(colModel, eventArgs) {
                    try {

                        if (isNullOrUndefined(colModel)) {
                            //TODO : log
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            //TODO : log
                            return;
                        }

                        //eventArgs.selectOptions = [];

                        


                        EventHandlers.raiseEvent(vpGrid.Event.onSelectCellRendering, vpGrid, eventArgs);

                        //check if the default options must be used



                        //check if new select options have been passed by the listener(s)
                        if (isNullOrUndefinedOrEmpty(eventArgs.selectOptions)) {
                            // get options value from all values in the current column
                            var colValues = jqGrid.colValues(colModel.name);
                            var optionsCount = colValues.length;
                            eventArgs.selectOptions = eventArgs.selectOptions || {};
                            for (var i = 0; i < optionsCount; i++) {
                                eventArgs.selectOptions.push({
                                    key: colValues[i],
                                    value: colValues[i]
                                });
                            }
                        }

                        var selectOptions = eventArgs.selectOptions;
                        var optionsCount = selectOptions.length;
                        var optionsValue = "";
                        for (var i = 0; i < optionsCount; i++) {
                            var selectOption = selectOptions[i];
                            optionsValue += selectOption.key + ':' + selectOption.value;
                            if (i < optionsCount - 1) {
                                optionsValue += ';';
                            }
                        }

                        //update  the colModel
                        colModel.editoptions = colModel.editoptions || {};
                        colModel.editoptions.value = optionsValue;
                        //save the key/value pairs collection on the colModel object directly (vpGrid extension)
                        colModel.selectKeyValues = eventArgs.selectOptions;


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function tryFindCurrentGridSchema() {
                    try {
                        var selector = "table[role=" + vpGrid.HtmlRoleAttribute.vpGridSchema + "]";
                        var jqElement = $(selector);

                        if (jqElement.found()) {
                            return jqElement;
                        }

                        vpGrid.logError({
                            message: "DOM element : <table role='" + vpGrid.HtmlRoleAttribute.vpGridSchema + "'> is missing. Please insert it in the Web page to activate the Excel grid."
                        });

                        return $(null);

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.initLocaleOptions = function () {
                    try {
                        if (isNullOrUndefinedOrEmpty(vpGrid.options)) {
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(vpGrid.options.jqGridOptions)) {
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(vpGrid.options.jqGridOptions.jgrid)) {
                            return;
                        }
                        var customOptions = vpGrid.options.jqGridOptions.jgrid;
                        if (isNullOrUndefinedOrEmpty(customOptions)) {
                            return;
                        }

                        try {
                            $.extend($.jgrid.formatter.date, customOptions.formatter.date);
                        } catch (e) {
                            vpGrid.logException(e);
                        }

                        try {
                            $.extend($.jgrid.formatter.currency, customOptions.formatter.currency);
                        } catch (e) {
                            vpGrid.logException(e);
                        }

                        try {
                            $.extend($.jgrid.formatter.integer, customOptions.formatter.integer);
                        } catch (e) {
                            vpGrid.logException(e);
                        }

                        try {
                            $.extend($.jgrid.formatter.number, customOptions.formatter.number);
                        } catch (e) {
                            vpGrid.logException(e);
                        }

                        try {
                            $.extend($.jgrid.formatter.checkbox, customOptions.formatter.checkbox);
                        } catch (e) {
                            vpGrid.logException(e);
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initMinColdWidthOption = function () {
                    try {
                        if (isNullOrUndefinedOrEmpty(jqGrid.options.minColWidth)) {
                            vpGrid.logError({
                                functionName: "jqGrid.initMinColdWithOption",
                                message: "property minColWidth is not defined in jqGrid.options",
                                info: "minColdWitdth is assigned a default value of 20 pixels"
                            })
                            jqGrid.options.minColWidth = 20;
                        }

                        if (isNullOrUndefinedOrEmpty(vpGrid.options)) {
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(vpGrid.options.minColWidth)) {
                            return;
                        }

                        var widthValue = vpGrid.options.minColWidth;
                        if (isNotInt(widthValue)) {
                            vpGrid.logError({
                                functionName: "jqGrid.initMinColdWithOption",
                                message: "property minColWidth is not defined or has not the correct format in vpGrid Options",
                                info: "minColdWitdth is assigned a default value of " + jqGrid.options.minColWidth + " pixels"
                            })
                            return;
                        }

                        jqGrid.options.minColWidth = vpGrid.options.minColWidth;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initWidthOption = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(vpGrid.options)) {
                            return;
                        }

                        if (isNotBoolean(vpGrid.options.fitToBrowserWidth)) {
                            return;
                        }

                        if (vpGrid.options.fitToBrowserWidth) {
                            jqGrid.options.autowidth = true;
                            return;
                        }

                        jqGrid.options.autowidth = false;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initShrinkToFitOption = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(vpGrid.options)) {
                            return;
                        }

                        if (isNotBoolean(vpGrid.options.fixedColWidth)) {
                            return;
                        }

                        if (vpGrid.options.fixedColWidth) {
                            jqGrid.options.shrinkToFit = false;
                            return;
                        }

                        jqGrid.options.shrinkToFit = true;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initRowCheckboxOption = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(vpGrid.options)) {
                            return;
                        }

                        if (isNotBoolean(vpGrid.options.enableRowCheckbox)) {
                            return;
                        }

                        if (vpGrid.options.enableRowCheckbox === false) {
                            jqGrid.options.multiselect = false;
                            jqGrid.options.multiboxonly = false;
                            return;
                        }

                        jqGrid.options.multiselect = true;
                        jqGrid.options.multiboxonly = true;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initToolbarOption = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(vpGrid.options)) {
                            return;
                        }

                        if (isNotBoolean(vpGrid.options.enableCustomStatusBar)) {
                            return;
                        }

                        if (vpGrid.options.enableCustomStatusBar === false) {
                            jqGrid.options.toolbar = [false, ""];
                            return;
                        }

                        jqGrid.options.toolbar = [true, "bottom"];

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initSummaryRowOption = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(vpGrid.options)) {
                            return;
                        }

                        if (isNotBoolean(vpGrid.options.enableSummaryRows)) {
                            return;
                        }

                        jqGrid.options.footerrow = false;
                        jqGrid.options.toprow = false;

                        if (vpGrid.options.enableSummaryRows) {
                            jqGrid.options.footerrow = true;
                        }

                        if (vpGrid.options.placeSummaryRowsOnTop) {
                            jqGrid.options.toprow = true;
                        }

                        jqGrid.options.numberOfSummaryRows = 1;
                        if (vpGrid.options.numberOfSummaryRows && vpGrid.options.numberOfSummaryRows > 1) {
                            jqGrid.options.numberOfSummaryRows = vpGrid.options.numberOfSummaryRows;
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initColumnReorderingOption = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(vpGrid.options)) {
                            return;
                        }

                        if (isNotBoolean(vpGrid.options.enableColumnReordering)) {
                            return;
                        }

                        if (vpGrid.options.enableColumnReordering === false) {
                            jqGrid.options.sortable = false;
                            return;
                        }

                        jqGrid.options.sortable = true;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initOptions = function () {
                    try {
                        jqGrid.initLocaleOptions();
                        jqGrid.initMinColdWidthOption();
                        jqGrid.initWidthOption();
                        jqGrid.initShrinkToFitOption();
                        jqGrid.initToolbarOption();
                        jqGrid.initRowCheckboxOption();
                        jqGrid.initSummaryRowOption();
                        jqGrid.initAutoInsertNewLine();
                        jqGrid.initColumnReorderingOption();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                var _jqGridHost = null; // DOM element that holds the jqGrid table
                jqGrid.host = function () {
                    /// <signature>
                    /// <summary>Get the TABLE that holds the jqGrid grid.</summary>
                    /// <returns type="Object">jQuery object that wraps the found TABLE element.</returns>
                    /// </signature>
                    try {
                        if (_jqGridHost != null) {
                            return $(_jqGridHost);
                        }

                        var jqGridHostSelector = "table[id=" + jqGrid.Id + "]";
                        var jqGridHost = $(jqGridHostSelector);

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "DOM element : <table id='" + jqGrid.Id + "'> is missing. jqGrid cannot be managed by vpGrid."
                            });
                        }

                        _jqGridHost = jqGridHost[0];
                        return jqGridHost;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.container = function () {
                    try {
                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridBody + "]";
                        var jqGridContainer = $(selector);

                        if (jqGridContainer.notFound()) {
                            vpGrid.logError({
                                message: "Selector not found : '" + jqGridContainer.selector + "'",
                                functionName: "jqGrid.container",
                                info: "Dom element : <div role='" + vpGrid.HtmlRoleAttribute.vpGridBody + "'> is missing. Please insert it in the Web page to activate the Excel grid."

                            });
                        }

                        return jqGridContainer;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.body = function () {
                    try {

                        var jqGridContainer = jqGrid.container();
                        var bodySelector = "div.ui-jqgrid-bdiv";
                        var jqBody = jqGridContainer.find(bodySelector);

                        if (jqBody.notFound()) {
                            vpGrid.logError({
                                message: "Selector not found : '" + bodySelector + "'",
                                functionName: "jqGrid.body"
                            });
                            return $(null);
                        }

                        return jqBody;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.ribbonContainer = function () {
                    /// <signature>
                    /// <summary>Get the vpGrid  Ribbon container</summary>
                    /// <returns type="Object">Returns the ribbon container found by jQuery</returns>
                    /// </signature>
                    try {

                        var jqGridContainer = vpGrid.currentContainer();
                        var ribbonSelector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridRibbon + "]";
                        var jqRibbon = jqGridContainer.find(ribbonSelector);

                        if (jqRibbon.notFound()) {
                            vpGrid.logError({
                                message: "Selector not found : '" + ribbonSelector + "'",
                                functionName: "jqGrid.ribbonContainer"
                            });
                            return $(null);
                        }

                        return jqRibbon;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.summaryRowsContainer = function () {
                    try {

                        if (jqGrid.options.footerrow === false) {
                            // there is no summary row
                            return $(null);
                        }

                        var jqGridContainer = jqGrid.container();
                        var summaryRowSelector = "div.ui-jqgrid-sdiv";
                        var jqSummaryRow = jqGridContainer.find(summaryRowSelector);

                        if (jqSummaryRow.notFound()) {
                            vpGrid.logError({
                                message: "Selector not found : '" + summaryRowSelector + "'",
                                functionName: "jqGrid.summaryRowsContainer"
                            });
                            return $(null);
                        }

                        return jqSummaryRow;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.headersContainer = function () {
                    try {
                        var jqGridContainer = jqGrid.container();
                        var headersTableSelector = "table.ui-jqgrid-htable";
                        var jqHeadersContainer = jqGridContainer.find(headersTableSelector);

                        if (jqHeadersContainer.notFound()) {
                            vpGrid.logError({
                                message: "Selector not found : '" + headersTableSelector + "'",
                                functionName: "jqGrid.headersContainer"
                            });
                            return $(null);
                        }

                        return jqHeadersContainer;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.summaryRows = function () {
                    /// <signature>
                    /// <summary>Get all summary rows.</summary>
                    /// <returns type="Object">Returns a jQuery object that holds the summary rows collection</returns>
                    /// </signature>
                    try {
                        if (jqGrid.options.footerrow === false) {
                            // there is no summary row
                            return $(null);
                        }

                        var jqSummaryRowsContainer = jqGrid.summaryRowsContainer();

                        if (jqSummaryRowsContainer.notFound()) {
                            vpGrid.logError({
                                message: "Cannot find the summary rows container.",
                                functionName: "jqGrid.summaryRows"
                            });
                            return $(null);
                        }

                        var summaryRowSelector = "tr[role=row].footrow";
                        var jqSummaryRows = jqSummaryRowsContainer.find(summaryRowSelector);

                        if (jqSummaryRows.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.summaryRows",
                                message: "Summary Rows not found in DOM. Summary rows Selector='" + summaryRowSelector + "'"
                            });
                        }

                        return jqSummaryRows;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.summaryCell = function (uiIdentifier,cellName) {
                    /// <signature>
                    /// <summary>Get cell from specific summary row and specific column.</summary>
                    /// <param name="uiIdentifier" type="String">The value of the data tag 'data-vpgrid-ui-id'. This parameter should be set to empty if there is only one summary row.</param>
                    /// <param name="cellName" type="String">Name of the column where the summary cell is.</param>
                    /// <returns type="Object">Returns a jQuery object representing the found summary cell.</returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(uiIdentifier)) {
                            uiIdentifier = "";
                        }

                        if (isNotString(uiIdentifier)) {
                            vpGrid.logError({
                                functionName: "jqGrid.summaryCell",
                                message: "uiIdentifier is not valid string :'" + uiIdentifier + "'"
                            });
                            return;
                        }

                        var jqSummaryRow = jqGrid.summaryRow(uiIdentifier);
                        var cellSelector = jqGrid.cellSelectorForCol( cellName );
                        var jqCell = jqSummaryRow.find(cellSelector);
                        if (jqCell.notFound()) {
                            vpGrid.logError({
                                message: "Summary Cell not found in DOM. Cell Selector='" + cellSelector + "'"
                            });
                        }

                        return jqCell;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.summaryRow = function (uiIdentifier) {
                    /// <signature>
                    /// <summary>Get the summary row with specified uiIdentifier.</summary>
                    /// <param name="uiIdentifier" type="String">The value of the data tag 'data-vpgrid-ui-id'. This parameter should be set to empty if there is only one summary row.</param>
                    /// <returns type="Object">Returns a jQuery object representing the found summary row.</returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(uiIdentifier)) {
                            uiIdentifier = "";
                        }

                        if (isNotString(uiIdentifier)) {
                            vpGrid.logError({
                                functionName: "jqGrid.summaryRow",
                                message: "uiIdentifier is not valid string :'" + uiIdentifier + "'"
                            });
                            return;
                        }

                        var jqSummaryRowsContainer = jqGrid.summaryRowsContainer();
                        var summaryRowSelector = "tr[role=row].footrow";
                        if (uiIdentifier.isNotNullOrEmptyOrWhitespace()) {
                            summaryRowSelector = "tr[role=row][data-vpgrid-ui-id=" + uiIdentifier + "].footrow";
                        }

                        var jqSummaryRow = jqSummaryRowsContainer.find(summaryRowSelector);
                        if (jqSummaryRow.notFound()) {
                            vpGrid.logError({
                                message: "Summary row not found in DOM. row Selector='" + summaryRowSelector + "'"
                            });
                        }

                        return jqSummaryRow;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.row = function (rowid) {
                    try {

                        if (isNullOrUndefinedOrEmpty(rowid)) {
                            vpGrid.logError({
                                functionName: "jqGrid.row",
                                message: "rowid is not valid id :'" + rowid + "'"
                            });
                            return $(null);
                        }

                        var jqGridHost = jqGrid.host();
                        var rowSelector = "tr[role=row][id=" + rowid + "]";
                        var jqRow = jqGridHost.find(rowSelector);

                        if (jqRow.notFound()) {
                            vpGrid.logError({
                                message: "jqGrid row not found in DOM. rowid='" + rowid + "'"
                            });
                        }
                        return jqRow;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.cellSelectorForCol = function (colName) {
                    /// <signature>
                    /// <summary>Get the CSS selector for a cell in the specified column.</summary>
                    /// <param name="colName" type="String">Name of the column in the grid.</param>
                    /// <returns type="String">jQuery CSS selector for the TD cell</returns>
                    /// </signature>
                    try {
                        var cellSelector = "td[role=gridcell][" + vpGrid.HtmlDataTag.ColumnName + "=" + colName + "]";
                        return cellSelector;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.searchInputSelectorForCol = function (colName) {
                    /// <signature>
                    /// <summary>Get the CSS selector for the search input field in the specified column.</summary>
                    /// <param name="colName" type="String">Name of the column in the grid.</param>
                    /// <returns type="String">jQuery CSS selector for the input search field</returns>
                    /// </signature>
                    try {
                        var inputSelector = "input[type=text][id=gs_" + colName + "]";
                        return inputSelector;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }


                jqGrid.defaultJqGridCellSelectorForCol = function (colName) {
                    /// <signature>
                    /// <summary>Get the CSS selector (generated by default by jqgrid) for a cell in the specified column.</summary>
                    /// <param name="colName" type="String">Name of the column in the grid.</param>
                    /// <returns type="String">jQuery CSS selector for the TD cell</returns>
                    /// </signature>
                    try {
                        var cellSelector = "td[role=gridcell][aria-describedby=" + jqGrid.Id + "_" + colName + "]";
                        return cellSelector;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }


                jqGrid.inlineSummaryCellSelectorForCol = function (colName) {
                    /// <signature>
                    /// <summary>Get the CSS selector for a cell in the specified column within an inline summary row. 
                    ///     An inline summary row is a summary row that is dynamically injected within the grid
                    /// </summary>
                    /// <param name="colName" type="String">Name of the column in the grid.</param>
                    /// <returns type="String">jQuery CSS selector for the TD cell</returns>
                    /// </signature>
                    try {
                        var cellSelector = "td[role=summarygridcell][" + vpGrid.HtmlDataTag.ColumnName + "=" + colName + "]";
                        return cellSelector;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.getRowThatHoldsItemWithKey = function (itemKey) {
                    /// <signature>
                    /// <summary>Get the jqGrid row that holds the item identified by its key itemKey.</summary>
                    /// <param name="itemKey" type="String">Key of the item to found in the grid</param>
                    /// <returns type="Object">jQuery object of the found table row</returns>
                    /// </signature>
                    try {

                        if (isNotString(itemKey)) {
                            vpGrid.logError({
                                functionName: "jqGrid.getRowThatHoldsItemWithKey",
                                message: "itemKey is not a valid string :'" + itemKey + "'"
                            });
                            return $(null);
                        }

                        //check if a key has been setup on the Key column
                        var keyColumnName = JQGrid.keyColumnName();
                        if (isNullOrUndefinedOrEmpty(keyColumnName)) {
                            vpGrid.logError({
                                functionName: "getRowThatHoldsItemWithKey",
                                message: "Key column not found.",
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnType + "=key'," + " must be defined in the column schema."
                            });
                            return $(null);
                        }

                        // get all cells in the Key column
                        var jqGridHost = jqGrid.host();
                        var itemsSelector = jqGrid.cellSelectorForCol(keyColumnName);
                        var jqItems = jqGridHost.find(itemsSelector);
                        var jqItemsCount = jqItems.length;
                        for (var i = 0; i < jqItemsCount; i++) {
                            var item = jqItems[i];
                            var jqItem = $(item);
                            var currentKey = jqItem.text();
                            if (itemKey === currentKey) {
                                var jqRow = jqItem.closest('tr[role = row]');
                                return jqRow;
                            }
                        }

                        vpGrid.logError({
                            functionName: "getRowThatHoldsItemWithKey",
                            message: "No row found from selector :'" + itemsSelector + "' with item key: '" + itemKey + "'"
                            
                        });

                        return $(null);

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.getRowThatHoldsItemWithData = function (dataRow) {
                    /// <signature>
                    /// <summary>Get the jqGrid row that holds the item identified by its data.</summary>
                    /// <param name="dataRow" type="Object">Literal object representing a data row and containing column values. 
                    ///                     Each property of this object should match a column name.
                    ///                     dataRow should at least contains the entity key 
                    /// </param>
                    /// <returns type="Object">jQuery object of the found table row</returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.getRowThatHoldsItemWithData",
                                message: "dataRow is not a valid data row :'" + dataRow + "'"
                            });
                            return $(null);
                        }

                        //check if a key has been setup on the Key column
                        var keyColumnName = JQGrid.keyColumnName();
                        if (isNullOrUndefinedOrEmpty(keyColumnName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.getRowThatHoldsItemWithData",
                                message: "Key column not found.",
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnType + "=key'," + " must be defined in the column schema."
                            });
                            return $(null);
                        }

                        if (isNullOrUndefinedOrEmpty(dataRow[keyColumnName])) {
                            vpGrid.logError({
                                functionName: "jqGrid.getRowThatHoldsItemWithData",
                                message: "The property dataRow." + keyColumnName + " was not found or its value is invalid : '" + dataRow[keyColumnName] + "'"
                            });
                            return $(null);
                        }

                        var itemKey = dataRow[keyColumnName];
                        if (isNotString(itemKey)) {
                            vpGrid.logError({
                                functionName: "jqGrid.getRowThatHoldsItemWithData",
                                message: "The property dataRow." + keyColumnName + " is not a string but is : '" + itemKey + "'"
                            });
                            return $(null);
                        }

                        var jqRow = jqGrid.getRowThatHoldsItemWithKey(itemKey);
                        return jqRow;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.removeClassForItemWithKey = function (itemKey, className) {
                    /// <signature>
                    /// <summary>Get the jqGrid row that holds the item identified by its key itemKey. Then remove the specified css class on the TR and TD children</summary>
                    /// <param name="itemKey" type="String">Key of the item to found in the grid</param>
                    /// <param name="className" type="String">Name of the CSS class to be removed from the TR element and all its TD children.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNotString(itemKey)) {
                            vpGrid.logError({
                                functionName: "jqGrid.removeClassForItemWithKey",
                                message: "itemKey is not a valid string :'" + itemKey + "'"
                            });
                            return ;
                        }

                        if (isNotString(className)) {
                            vpGrid.logError({
                                functionName: "jqGrid.removeClassForItemWithKey",
                                message: "className is not a valid string :'" + className + "'"
                            });
                            return;
                        }

                        var jqRow = jqGrid.getRowThatHoldsItemWithKey(itemKey);

                        if (jqRow.notFound()) {
                            return;
                        }

                        jqRow.removeClass(className);
                        jqRow.find("td[role=gridcell]").removeClass(className);


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.addClassForItemWithKey = function (itemKey, className) {
                    /// <signature>
                    /// <summary>Get the jqGrid row that holds the item identified by its key itemKey. Then add the specified css class on the TR and TD children</summary>
                    /// <param name="itemKey" type="String">Key of the item to found in the grid</param>
                    /// <param name="className" type="String">Name of the CSS class to be added to the TR element and all its TD children.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNotString(itemKey)) {
                            vpGrid.logError({
                                functionName: "jqGrid.addClassForItemWithKey",
                                message: "itemKey is not a valid string :'" + itemKey + "'"
                            });
                            return;
                        }

                        if (isNotString(className)) {
                            vpGrid.logError({
                                functionName: "jqGrid.addClassForItemWithKey",
                                message: "className is not a valid string :'" + className + "'"
                            });
                            return;
                        }

                        var jqRow = jqGrid.getRowThatHoldsItemWithKey(itemKey);

                        if (jqRow.notFound()) {
                            return;
                        }

                        var rowid = jqRow[0].id;

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: 'jqGrid.addClassForItemWithKey',
                                message: "ColModels not found."
                            });
                            return ;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            if (colModel.isKey) {
                                continue;
                            }

                            if (colModel.hidden === true) {
                                continue;
                            }

                            if (colModel.isAction) {
                                continue;
                            }

                            var jqCell = jqGrid.cell(rowid, colModel.name);
                            jqCell.addClass(className);

                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.currrentRow = function () {
                    try {

                        var jqRow = jqGrid.row(jqGrid.currentRowId);
                         
                        if (jqRow.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.currrentRow",
                                message: "Current selected row cannot be found"
                            });
                            return $(null);
                        }

                        return jqRow;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.selectedRow = function () {
                    /// <signature>
                    /// <summary>Get the row from the first selected Item.
                    ///         A selected item is a row for which the first column checkbox has been checked.
                    ///         This function is not the same as jqGrid.currentRow.
                    ///             ->jqGrid.currentRow returns the row where a cell has been clicked either for edition or for any other process started on click event.
                    ///</summary>
                    /// <returns type="Object">Returns a jQuery object of the found table row</returns>
                    /// </signature>
                    try {
                        // get the jqGrid host table
                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot get selected row because jqGrid host is not found."
                            });
                            return $(null);
                        }


                        var checkboxSelector = "input[type=checkbox][id=" + jqGrid.currentSelectedCheckboxId + "]";
                        var jqCheckbox = jqGridHost.find(checkboxSelector);

                        if (jqCheckbox.notFound()) {
                            //TODO : log
                            return $(null);
                        }


                        var jqRow = jqCheckbox.closest("tr[role=row]");

                        if (jqRow.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.selectedRow",
                                message: "Current selected row cannot be found."
                            });
                            return $(null);
                        }

                        return jqRow;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.cell = function (rowid, cellName) {
                    /// <signature>
                    /// <summary>Get the cell located in a specific row and in a specific column.</summary>
                    /// <param name="rowid" type="String">The id of the row (DOM id) where the cell is located</param>
                    /// <param name="cellname" type="String">Name of the column where the cell is located.</param>
                    /// <returns type="Object">Returns a jQuery object corresponding to the cell.</returns>
                    /// </signature>
                    try {
                        if (isNotString(cellName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.cell",
                                message: "cellName is not valid string :'" + cellName + "'"
                            });
                            return $(null);
                        }

                        var jqRow = jqGrid.row(rowid);
                        var cellSelector = jqGrid.cellSelectorForCol( cellName);
                        var jqCell = jqRow.find(cellSelector);
                        if (jqCell.notFound()) {
                            vpGrid.logError({
                                functionName : "jqGrid.cell",
                                message: "Cell not found in DOM. Cell Selector='" + cellSelector + "', rowid='" + rowid +"'"
                            });
                        }

                        return jqCell;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.cellValue = function (rowid, cellName) {
                    /// <signature>
                    /// <summary>Get the value of the cell located in a specific row and in a specific column.</summary>
                    /// <param name="rowid" type="String">The id of the row (DOM id) where the cell is located</param>
                    /// <param name="cellname" type="String">Name of the column where the cell is located.</param>
                    /// <returns type="Object">Returns the value in native format.</returns>
                    /// </signature>
                    try {
                        if (isNotString(cellName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.cellValue",
                                message: "cellName is not valid string :'" + cellName + "'"
                            });
                            return $(null);
                        }

                        //check if the row exists
                        var jqRow = jqGrid.row(rowid);

                        var jqGridHost = jqGrid.host();
                        var cellValue = jqGridHost.jqGrid('getCell', rowid, cellName);

                        return cellValue;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.inlineSummaryCell = function (rowid, cellName) {
                    try {
                        if (isNotString(cellName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.cell",
                                message: "cellName is not valid string :'" + cellName + "'"
                            });
                            return $(null);
                        }

                        var jqRow = jqGrid.row(rowid);
                        var cellSelector = jqGrid.inlineSummaryCellSelectorForCol( cellName);
                        var jqCell = jqRow.find(cellSelector);
                        if (jqCell.notFound()) {
                            vpGrid.logError({
                                message: "Cell not found in DOM. Cell Selector='" + cellSelector + "'"
                            });
                        }

                        return jqCell;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.cellValueIsInRange = function (rowid,cellName, cellValue, colModel) {
                    /// <signature>
                    /// <summary>Check if cell value is in the range defined by minValue and maxValue of the column schema.</summary>
                    /// <param name="rowid" type="String">HTML Id of the row where the cell is.</param>
                    /// <param name="cellName" type="String">Name of the column where the cell is.</param>
                    /// <param name="cellValue" type="String">Value of the cell being rendered by jqGrid</param>
                    /// <param name="colModel" type="Object">Column model of the cell</param>
                    /// <returns type="Boolean">Returns true if cell value is in range or if no range is defined.</returns>
                    /// </signature>
                    try {
                        if (isNotString(cellName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.cellValueIsInRange",
                                message: "cellName is not valid string :'" + cellName + "'"
                            });
                            return false;
                        }

                        if (colModel.isKey) {
                            return true;
                        }

                        if (colModel.isRequired === true && cellValue === null) {
                            return false;
                        }

                        if (colModel.isRequired === true && cellValue === undefined) {
                            return false;
                        }

                        if (colModel.isRequired === true && cellValue === '') {
                            return false;
                        }


                        if (colModel.isString && colModel.isRequired === true && isNullOrUndefinedOrEmpty(cellValue)) {
                            return false;
                        }

                        if (colModel.isString && colModel.isRequired === true && isString(cellValue) && cellValue.isNullOrEmptyOrWhitespace()) {
                            return false;
                        }

                        if (colModel.isString) {
                            return true;
                        }

                        if (colModel.isDate && colModel.isRequired === true && isString(cellValue) && cellValue.isNullOrEmptyOrWhitespace()) {
                            return false;
                        }

                        if (colModel.isDate) {
                            //TODO : implement Date range computation
                            return true;
                        }

                        if (colModel.isCheckbox) {
                            return true;
                        }

                        if (colModel.isNote) {
                            return true;
                        }

                        if (colModel.isLink) {
                            return true;
                        }

                        if (colModel.isImage) {
                            return true;
                        }

                        if (colModel.isAction) {
                            return true;
                        }

                        //check if the column content is not required
                        if (colModel.isRequired === false && cellValue === null ) {
                            return true;
                        }

                        if (colModel.isRequired === false && cellValue === undefined) {
                            return true;
                        }

                        if (colModel.isRequired === false && cellValue === '') {
                            return true;
                        }

                        // now we are sure column is numeric
                        var editrules = colModel.editrules || {};
                        var minValue = editrules.minValue;
                        var maxValue = editrules.maxValue;
                        if (isInRange(cellValue, minValue, maxValue)) {
                            return true;
                        }

                        return false;
                        
                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.cellValueIsOutOfRange = function (rowid,cellName, cellValue, colModel){
                    /// <signature>
                    /// <summary>Check if cell value is not in the range defined by minValue and maxValue of the column schema.</summary>
                    /// <param name="rowid" type="String">HTML Id of the row where the cell is.</param>
                    /// <param name="cellName" type="String">Name of the column where the cell is.</param>
                    /// <param name="cellValue" type="String">Value of the cell being rendered by jqGrid</param>
                    /// <param name="colModel" type="Object">Column model of the cell</param>
                    /// <returns type="Boolean">Returns true if cell value is not in range. Returns false if no range is defined in the column schema.</returns>
                    /// </signature>
                    return jqGrid.cellValueIsInRange(rowid,cellName, cellValue, colModel) === false;
                }

                jqGrid.setCell = function (rowid, cellName, cellValue) {
                    /// <signature>
                    /// <summary>Set the cell content with input value cellValue</summary>
                    /// <param name="rowid" type="String">The id of the row where the cell is located.</param>
                    /// <param name="cellname" type="String">Name of the cell to change. This name is defined in the colModel of the corresponding column.</param>
                    /// <param name="cellValue" type="String">Value to insert in cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNotString(cellName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.setCell",
                                message: "cellName is not valid string :'" + cellName + "'"
                            });
                            return ;
                        }

                        var jqGridHost = jqGrid.host();
                        
                        //TODO : raise event to gather CSS class and td attributes
                        jqGridHost.jqGrid("setCell", rowid, cellName, cellValue, false, false, true);

                        //TODO : re-validate cell content with OOB validators ( required/min/max)
                        var colModel = jqGrid.colModelOf(cellName);
                        if (jqGrid.cellValueIsInRange(rowid, cellName, cellValue, colModel)) {
                            var jqCell = jqGrid.cell(rowid, cellName);
                            jqCell.removeClass('ui-state-error');
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                        return;
                    }
                }

                jqGrid.setFooterData = function (uiIdentifier, userData, useCellFormatter) {
                    /// <signature>
                    /// <summary>Set summary row content with data from userData</summary>
                    /// <param name="uiIdentifier" type="String">The value of the data tag 'data-vpgrid-ui-id'. This parameter should be set to empty if there is only one summary row.</param>
                    /// <param name="userData" type="Array">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <param name="useCellFormatter" type="Boolean">If set to true, the values are rendered using the formatters declared in the col schema columns.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(uiIdentifier)) {
                            uiIdentifier = "";
                        }

                        if (isNotString(uiIdentifier)) {
                            vpGrid.logError({
                                functionName: "jqGrid.setFooterData",
                                message: "uiIdentifier is not valid string :'" + uiIdentifier + "'"
                            });
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        if (uiIdentifier.isNullOrEmptyOrWhitespace()) {
                            jqGridHost.jqGrid("footerData", "set", userData, useCellFormatter);
                            return;
                        }
                        
                        jqGridHost.jqGrid("footerData2", "set", userData, useCellFormatter, uiIdentifier);

                    } catch (e) {
                        vpGrid.logException(e);
                        return;
                    }
                }

                jqGrid.showCol = function (colName) {
                    /// <signature>
                    /// <summary>Show in the UI the column named colName</summary>
                    /// <param name="colName" type="String">Name of the column to show. This name is defined in the colModel of the corresponding column.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNotString(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.showCol",
                                message: "colName is not valid string :'" + colName + "'"
                            });
                            return;
                        }

                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.showCol",
                                message: "colName '" + colName + "' is not defined as a jqGrid column",
                                info: "Check the columns schema in your Web Page."
                            });
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        //TODO : raise event onColumnShowing
                        jqGridHost.jqGrid("showCol", colName);


                    } catch (e) {
                        vpGrid.logException(e);
                        return;
                    }
                }

                jqGrid.hideCol = function (colName) {
                    /// <signature>
                    /// <summary>Hide in the UI the column named colName</summary>
                    /// <param name="colName" type="String">Name of the column to hide. This name is defined in the colModel of the corresponding column.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNotString(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.showCol",
                                message: "colName is not valid string :'" + colName + "'"
                            });
                            return;
                        }

                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.showCol",
                                message: "colName '" + colName + "' is not defined as a jqGrid column",
                                info: "Check the columns schema in your Web Page."
                            });
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        //TODO : raise event onColumnHiding
                        jqGridHost.jqGrid("hideCol", colName);


                    } catch (e) {
                        vpGrid.logException(e);
                        return;
                    }
                }

                jqGrid.resizeCol = function (colName, width) {
                    /// <signature>
                    /// <summary>Resize in the UI the column named colName.</summary>
                    /// <param name="colName" type="String">Name of the column to resize. This name is defined in the colModel of the corresponding column.</param>
                    /// <param name="width" type="Integer">New width of the column</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNotString(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.resizeCol",
                                message: "colName is not valid string :'" + colName + "'"
                            });
                            return;
                        }

                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.resizeCol",
                                message: "colName '" + colName + "' is not defined as a jqGrid column",
                                info: "Check the columns schema in your Web Page."
                            });
                            return;
                        }

                        

                        // get the index of the column in the DOM
                        var colIndex = jqGrid.colIndexOf(colName);
                        if (colIndex < 0) {
                            vpGrid.logError({
                                functionName: "jqGrid.resizeCol",
                                message: "colName '" + colName + "' has a negative col index.",
                                info: "Check the columns schema in your Web Page."
                            });
                            return;
                        }

                        var jqGridHost = jqGrid.host();
                        var firstRow = jqGridHost[0].rows[0];
                        $(firstRow).find("td:eq(" + colIndex + ")").css('width', width);

                        var jqGridSummaryRowsHost = jqGrid.summaryRowsContainer();
                        jqGridSummaryRowsHost.find("tr.footrow").find("td:eq(" + colIndex + ")").css('width', width);

                        var jqGridHeadersHost = jqGrid.headersContainer();
                        jqGridHeadersHost.find("tr.ui-jqgrid-labels").find("th:eq(" + colIndex + ")").css('width', width);

                    } catch (e) {
                        vpGrid.logException(e);
                        return;
                    }
                }

                jqGrid.contentArea = function () {
                    try {
                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot get jqGrid contentArea because jqGrid host is not found."
                            });
                            return $(null);
                        }

                        var jqElement = jqGridHost.closest("div");

                        return jqElement;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.init = function () {
                    try {
                        jqGrid.isReady = false;

                        jqGrid.initData();

                        //find DOM element where to plug the jqGrid component
                        var jqGridSchema = tryFindCurrentGridSchema();
                        var jqGridRootNode = jqGridSchema.parent();

                        if (jqGridSchema.notFound()) {
                            //TODO : log
                            return;
                        }

                        //load jqGrid options
                        jqGrid.initOptions();

                        //Build the column models
                        buildColModels();

                        //Init the width of the grid (can be done only after buildColModels call
                        jqGrid.initWidth();

                        //Init the height of the grid (can be done only after buildColModels call
                        jqGrid.initHeight();

                        //Setup default Caption
                        if (vpGrid.options.defaultCaption) {
                            jqGrid.options.caption = vpGrid.options.defaultCaption;
                        }

                        //extract the custom grid caption schema
                        var customCaptionSelector = "[role=" + vpGrid.HtmlRoleAttribute.vpGridSchemaCaption + "]";
                        var customCaptionGrid = $(customCaptionSelector).detach();

                        //extract the custom grid status bar
                        var customStatusBarSelector = "[role=" + vpGrid.HtmlRoleAttribute.vpGridSchemaStatusBar + "]";
                        var customStatusBar = $(customStatusBarSelector).detach();

                        //extract the group headers description -> because they must be injected after calling jqGrid constructor
                        var groupHeadersSelector = "tr[role=" + vpGrid.HtmlRoleAttribute.vpGridSchemaColumnsGroup + "] ";
                        var customGroupHeaders = $(groupHeadersSelector).detach();

                        //detach the schema table from DOM
                        jqGridSchema.detach();

                        //dynamically add an empty table to host jqGrid in the DOM
                        var table = '<table id="' + jqGrid.Id + '"></table>';
                        var jqGridHost = $(table);
                        jqGridRootNode.append(jqGridHost);

                        //Create jqGrid
                        //TODO : raise event to enable listeners inspect and/or modify the jqGrid options
                        jqGridHost.jqGrid(jqGrid.options);

                        //inject custom Caption
                        if (customCaptionGrid.found() && vpGrid.options.enableCustomCaption) {
                            var jqGridCaptionSelector = "span.ui-jqgrid-title";
                            var jqGridCaption = $(jqGridCaptionSelector).first();
                            jqGridCaption.html("");
                            customCaptionGrid.appendTo(jqGridCaption);
                        }

                        //inject custom group headers
                        var groupHeadersOptions = buildGroupHeadersOptions(customGroupHeaders);
                        if (isNotNullOrUndefinedOrEmpty(groupHeadersOptions)) {
                            jqGridHost.jqGrid('setGroupHeaders', groupHeadersOptions);
                            // inject special css tag to be able to customize the rendering of the group headers
                            jqGridRootNode.find("tr[role=rowheader]").first().find("th[role=columnheader]").addClass('vpgrid-group-header');

                        }

                        //inject custom Status Bar
                        if (customStatusBar.found() && vpGrid.options.enableCustomStatusBar) {
                            //inject css class in bottom toolbar
                            var jqGridBottomToolbarSelector = "div[id=t_" + jqGrid.Id + "]";
                            var jqGridBottomToolbar = $(jqGridBottomToolbarSelector);
                            jqGridBottomToolbar.addClass('vpgrid-status-bar');
                            jqGridBottomToolbar.html("");
                            customStatusBar.appendTo(jqGridBottomToolbar);
                        }

                        //activate search filter toolbar on columns
                        if (vpGrid.options.enableFilterToolbar) {
                            var filterToolbarOptions = { stringResult: true, searchOnEnter: false, defaultSearch: 'cn', ignoreCase: true };
                            if (vpGrid.options.enableOperatorsInFilterToolbar) {
                                filterToolbarOptions.searchOperators = true;
                            }
                            jqGridHost.jqGrid('filterToolbar', filterToolbarOptions);
                            // inject special css tag to be able to customize the rendering of the filterToolbar
                            jqGridRootNode.find("table.ui-search-table").closest("th[role=columnheader]").addClass('vpgrid-filter-toolbar');
                        }

                        //activate frozen column --> does not work in this version
                        if (jqGrid.hasFrozenColumns) {
                            jqGridHost.jqGrid('setFrozenColumns');
                        }


                        //hide header checkbox if needed
                        if (vpGrid.options.enableMultiSelect === false) {
                            jqGrid.hideHeaderCheckbox();
                        }

                        //inject custom CSS in summary footer row container
                        if (vpGrid.options.enableSummaryRows) {
                            //inject css class in summary row
                            var jqSummaryRowsContainer = jqGrid.summaryRowsContainer();
                            jqSummaryRowsContainer.addClass('vpgrid-summary-rows');
                        }

                        if (vpGrid.options.enableSummaryRows) {
                            //tag the default summary row with specific vpgrid data tag
                            jqGrid.tagCellsInDefaultSummaryRow();

                            //add any additional summary rows if needed
                            jqGrid.createAdditionalSummaryRows();
                        }



                        //move summary rows on top if needed
                        jqGrid.placeSummaryRowsOnTop();

                        //TODO : bind qtip on column header if needed


                        //TODO : show welcome message window if needed

                        

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initData = function () {
                    try {

                        jqGrid.originalData = [];
                        jqGrid.updatedData = [];
                        jqGrid.deletedData = [];
                        jqGrid.insertedData = [];
                        jqGrid.insertedDataWithValidationErrors = [];
                        jqGrid.updatedDataWithValidationErrors = [];
                        jqGrid.filteredData = [];

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.getData = function () {
                    /// <signature>
                    /// <summary>Get all the data arrays stored by vpGrid and by jqGrid.
                    ///     This method must be used only for test purpose or for debug purpose
                    ///     You should never modify the returned data. 
                    /// </summary>
                    /// <returns type="Object">Literal object with the following signature
                    ///         {
                    ///              originalData: -> the data sent by the server
                    ///              updatedData:  -> the data that was updated in the grid and needs to be updated on server
                    ///              deletedData:  -> the data that was deleted in the grid and needs to be deleted on server
                    ///              insertedData: -> the data that was inserted in the grid and needs to be inserted on server
                    ///              insertedDataWithValidationErrors : -> the data that was inserted in the grid but not validated
                    ///              updatedDataWithValidationErrors : -> the data that was updated in the grid but not validated
                    ///              localData:    -> the data used by jqGrid to show items in the grid
                    ///              localIndexes: -> key/value collection where key is a row HTML id and value is the index of the corresponding data in localData.
                    ///              filteredData: -> the data filtered in the grid
                    ///         }
                    /// </returns>
                    /// </signature>
                    try {

                        var internalData = {
                            originalData: jqGrid.originalData,
                            updatedData: jqGrid.updatedData,
                            deletedData: jqGrid.deletedData,
                            insertedData: jqGrid.insertedData,
                            insertedDataWithValidationErrors: jqGrid.insertedDataWithValidationErrors,
                            updatedDataWithValidationErrors: jqGrid.updatedDataWithValidationErrors,
                            filteredData: jqGrid.filteredData
                        };

                        var jqGridHost = jqGrid.host();
                        if (jqGridHost.notFound()) {
                            return internalData;
                        }

                        var gridTable = jqGridHost[0];
                        if (gridTable.p && gridTable.p.data) {
                            internalData.localData = gridTable.p.data;
                        }

                        if (gridTable.p && gridTable.p._index) {
                            internalData.localIndexes = gridTable.p._index;
                        }

                        return internalData;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.getSchema = function () {
                    /// <signature>
                    /// <summary>Get the jqGrid col models array.
                    ///     This method must be used only for test purpose or for debug purpose
                    ///     You should never modify the returned data. 
                    /// </summary>
                    /// <returns type="Object">Literal object with the following signature
                    ///         {
                    ///              colTitles: -> string array. Each string is the title column
                    ///              colModels: -> array of literal objects. Each object stores the configuration of a column
                    ///         }
                    /// </returns>
                    /// </signature>
                    try {

                        var schema = {
                            
                        };

                        var jqGridHost = jqGrid.host();
                        if (jqGridHost.notFound()) {
                            return schema;
                        }

                        var gridTable = jqGridHost[0];
                        if (gridTable.p && gridTable.p.colModel) {
                            schema.colModels = gridTable.p.colModel;
                        }

                        if (gridTable.p && gridTable.p.colNames) {
                            schema.colTitles = gridTable.p.colNames;
                        }

                        return schema;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.initWidth = function () {
                    try {

                        if (jqGrid.hasFrozenColumns) {
                            jqGrid.options.shrinkToFit = false;
                        }


                        if (jqGrid.options.autowidth === true) {
                            return;
                        }

                        // sum all col width
                        var gridWidth = 0;
                        var colModels = jqGrid.options.colModel;
                        var colModelsCount = colModels.length;
                        for (var i = 0; i < colModelsCount; i++) {
                            var colModel = colModels[i];
                            // check if the col is hidden 
                            if (colModel.hidden === true) {
                                continue;
                            }
                            gridWidth += colModel.width;
                        }

                        // left and right column
                        gridWidth += 50;

                        jqGrid.options.width = gridWidth;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initHeight = function () {
                    try {
                        if (isNullOrUndefinedOrEmpty(vpGrid.options)) {
                            return;
                        }

                        if (isNotNumber(vpGrid.options.numberOfVisibleRows)) {
                            return;
                        }

                        jqGrid.options.height = jqGrid.options.rowHeight * vpGrid.options.numberOfVisibleRows - 3;

                        if (vpGrid.options.enableSummaryRows) {
                            jqGrid.options.height += 3;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initAutoInsertNewLine = function () {
                    try {
                        if (isNullOrUndefinedOrEmpty(vpGrid.options)) {
                            return;
                        }

                        if (isNotBoolean(vpGrid.options.autoInsertNewLineAtBottom)) {
                            return;
                        }

                        jqGrid.options.autoInsertNewLineAtBottom = vpGrid.options.autoInsertNewLineAtBottom;


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.isValidColumnType = function (colType) {
                    try {
                        var validColTypes = ["string", "checkbox", "key", "currency", "date", "number", "year", "action", "note", "int", "link", "image", "actionValidator"];

                        if (isNotString(colType)) {
                            vpGrid.logError({
                                functionName: "jqGrid.isValidColumnType",
                                message: "Column type '" + colType + "' is not valid because it is not a string",
                                info: "Valid column types are :" + validColTypes.toString() + "."
                            });
                            return false;
                        }


                        if (colType.isInArray(validColTypes)) {
                            return true;
                        }

                        vpGrid.logError({
                            functionName: "jqGrid.isValidColumnType",
                            message: "Column type '" + colType + "' is not valid because it is unknown.",
                            info: "Valid column types are :" + validColTypes.toString() + "."
                        });
                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.isNotValidColumnType = function (colType) {
                    return jqGrid.isValidColumnType(colType) === false;
                }

                jqGrid.isValidColumnName = function (colName) {
                    try {
                        if (isNotString(colName)) {
                            return false;
                        }

                        if (colName === "id") {
                            vpGrid.logError({
                                message: "'id' is a reserved name for jqGrid."
                            });
                            return false;
                        }

                        if (colName === "cb" && jqGrid.options.multiselect) {
                            vpGrid.logError({
                                message: "'cb' is a reserved name for a column when row checkbox is enabled."
                            });
                            return false;
                        }

                        if (colName === "subgrid") {
                            vpGrid.logError({
                                message: "'subgrid' is a reserved name for a column."
                            });
                            return false;
                        }

                        if (colName === "rn") {
                            vpGrid.logError({
                                message: "'rn' is a reserved name for a column."
                            });
                            return false;
                        }

                        if (colName === "files") {
                            vpGrid.logError({
                                message: "'files' is a reserved name for a column."
                            });
                            return false;
                        }

                        return true;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.isNotValidColumnName = function (colName) {
                    return jqGrid.isValidColumnName(colName) === false;
                }

                jqGrid.insertNewRow = function (dataRow, pos) {
                    /// <signature>
                    /// <summary>Insert a new row in the grid</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <param name="pos" type="String">Position of insertion. Valid values are : 'last' and 'first'</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRow",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                        if (isNotString(pos)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRow",
                                message: "Position parameter is not valid. Its value is :'" + pos + "'.",
                                info: "Position parameter is forced to value :'last'"
                            });
                            pos = 'last';
                        }

                        var allowedValues = ['first', 'last'];
                        if (pos.isNotInArray(allowedValues)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRow",
                                message: "Position parameter is not valid. Its value is :'" + pos + "'.",
                                info: "Valid values are : " + allowedValues.toString()
                            });
                            return;
                        }

                        //check if a key has been setup on the Key column
                        var keyColumnName = jqGrid.keyColumnName();
                        if (isNullOrUndefinedOrEmpty(keyColumnName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRow",
                                message: "The Key column name is null or undefined or empty.",
                                info: "Check that a key column has been correctly configured in the <tr role=vpgrid-schema-columns>"
                            });
                            // dynamically add a property to hold our own client primary key
                            dataRow['clientId'] = 'clientId' + vpGrid.guid++;
                        }

                        if (isNotNullOrUndefinedOrEmpty(keyColumnName) && isNullOrUndefinedOrEmpty(dataRow[keyColumnName])) {
                            dataRow[keyColumnName] = 'clientId' + vpGrid.guid++;
                        }

                        var jqGridHost = jqGrid.host();
                        var inserted = jqGridHost.jqGrid('addRowData', undefined, dataRow, pos);

                        if (inserted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRow",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }

                        jqGrid.totalItemCount += 1;
                        //set number of rows in jqGrid
                        var gridOptions = {
                            rowNum: jqGrid.totalItemCount
                        };
                        jqGridHost.jqGrid('setGridParam', gridOptions);


                        // update search input fields
                        jqGrid.updateSearchInputDataSourcesWithDataRow(dataRow);

                        //TODO : refresh the grid with current filters



                        //check if this item is the first row in an empty grid
                        if (jqGrid.totalItemCount === 1) {
                            //hideEmptyMessageOnGridComplete();
                            hideEmptyMessageOnLoad();
                        }

                        //update internal CRUD arrays 
                        jqGrid.updateDataWithInsertedRow(dataRow);

                        if (vpGrid.options.enableAutomaticPropagationOfUpdateInsertDeleteOperations === true) {
                            // grid is online
                            jqGrid.updateInsertDeleteDataOnRemote();
                            return;
                        }
                       
                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.validateDataRow = function (dataRow) {
                    /// <signature>
                    /// <summary>Validate all fields of the row represented by the input dataRow.</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <returns type="Object">Returns a literal object with the following signature
                    ///             {
                    ///                 isValid : true|false
                    ///                 errors : [] -> array of strings containing all errors in the dataRow
                    ///             }
                    /// </returns>
                    /// </signature>
                    try {
                        var validationResult = {
                            isValid: true,
                            errors : []
                        };

                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.validateDataRow",
                                message: "input dataRow is either null or undefined or empty."
                            });
                            validationResult.isValid = false;
                            validationResult.errors.push("internal error");
                            return validationResult;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: "jqGrid.validateDataRow",
                                message: "ColModels not found."
                            });
                            validationResult.isValid = false;
                            validationResult.errors.push("internal error");
                            return validationResult;
                        }

                        var colsCount = colModels.length;
                        for (var i = 0; i < colsCount; i++) {
                            var colModel = colModels[i];
                            var colName = colModel.name;

                            if (colName === 'cb') {
                                continue;
                            }
                            if (colModel.isKey === true) {
                                continue;
                            }

                            if (colModel.hidden === true) {
                                continue;
                            }

                            if (colModel.isAction === true) {
                                continue;
                            }

                            if (colModel.isActionValidator === true) {
                                continue;
                            }

                            if (colModel.editable === false) {
                                continue;
                            }

                            var cellValue = dataRow[colName];

                            if (isNullOrUndefinedOrEmpty(cellValue)) {
                                cellValue = '';
                            }

                            var jqGridTable = JQGrid.host();
                            var jqGridValidationResult = $.jgrid.checkValues.call(jqGridTable[0], cellValue, colName,undefined,undefined ,dataRow);
                            if (isNullOrUndefinedOrEmpty(jqGridValidationResult)) {
                                //TODO : log
                                continue;
                            }

                            if (jqGridValidationResult[0] === false) {
                                validationResult.isValid = false;
                                validationResult.errors.push({
                                    propertyName: colName,
                                    message: jqGridValidationResult[1]
                                });
                                continue;
                            }

                        } // end for (var i = 0; i < colsCount; i++) {

                        if (validationResult.isValid === false) {
                            return validationResult;
                        }

                        //TODO : raise event to enable custom business validation
                        var eventArgs = {
                            rowData: dataRow,
                            isValid: true,
                            errors: []
                        };

                        //raise event
                        onDataRowValidating(eventArgs);

                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "jqGrid.validateDataRow",
                                message: "eventArgs object corrupted by listener"
                            });
                            return validationResult;
                        }

                        if (isNotBoolean(eventArgs.isValid)) {
                            vpGrid.logError({
                                functionName: "jqGrid.validateDataRow",
                                message: "eventArgs.isValid property corrupted by listener"
                            });
                            return validationResult;
                        }

                        if (eventArgs.isValid) {
                            return validationResult;
                        }

                        validationResult.isValid = false;
                        validationResult.errors = eventArgs.errors;
                        return validationResult;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.showValidationErrorsForDataRow = function (validationResult, dataRow) {
                    try {
                        var jqRow = jqGrid.getRowThatHoldsItemWithData(dataRow)

                        if (jqRow.notFound()) {
                            //TODO : log
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(validationResult)) {
                            vpGrid.logError({
                                functionName: "jqGrid.showValidationErrorsForDataRow",
                                message: "validationResult is null or empty or undefined : '" + validationResult + "'"
                            });
                        }

                        if (validationResult.isValid === true) {
                            
                            return;
                        }

                        var errorsCount = validationResult.errors.length;
                        var rowid = jqRow[0].id;
                        for (var i = 0; i < errorsCount; i++) {
                            var error = validationResult.errors[i];
                            var colName = error.propertyName;
                            var jqCell = jqGrid.cell(rowid, colName);
                            jqCell.addClass('ui-state-error');
                            var errorMessage = error.message;
                            vpGrid.showUINotificationAtElement(jqCell[0], "", errorMessage);
                        }

                        
                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.insertDataOnRemote = function () {
                    try {

                        if (jqGrid.hasNoRemoteOperationPending()) {
                            var eventArgs = {};
                            onDataInsertedUpdatedDeletedOnRemote(vpGrid, eventArgs);
                        }

                        if (isNullOrUndefinedOrEmpty(jqGrid.insertedData)) {
                            // there is nothing to do
                            return;
                        }

                        var dataRow = jqGrid.insertedData[0];

                        if (vpGrid.options.enableInlineValidationOnInsert === false) {
                            jqGrid.insertDataOnRemoteWith(dataRow);
                            return;
                        }

                        //validate datarow
                        var validationResult = jqGrid.validateDataRow(dataRow);

                        if (isNullOrUndefined(validationResult)) {
                            //do not prevent sending data to server because of internal error
                            jqGrid.insertDataOnRemoteWith(dataRow);
                            return;
                        }


                        if (validationResult.isValid === true) {
                            jqGrid.insertDataOnRemoteWith(dataRow);
                            return;
                        }

                        //validation failed : move datarow to sandbox
                        var insertedDataRow = jqGrid.insertedData.shift();
                        jqGrid.insertedDataWithValidationErrors.push(insertedDataRow);

                        //show validation errors in the grid
                        jqGrid.showValidationErrorsForDataRow(validationResult, insertedDataRow)

                        // continue remote operations
                        executeAsync(this, jqGrid.insertDataOnRemote, 0);
                        
                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.updateDataOnRemote = function () {
                    try {


                        if (jqGrid.hasNoRemoteOperationPending()) {
                            var eventArgs = {};
                            onDataInsertedUpdatedDeletedOnRemote(vpGrid, eventArgs);
                        }

                        if (isNullOrUndefinedOrEmpty(jqGrid.updatedData)) {
                            // there is nothing to do
                            return;
                        }

                        var dataRow = jqGrid.updatedData[0];
                        jqGrid.updateDataOnRemoteWith(dataRow);
                        //TODO : DO NOT REMOVE THIS RETURN UNTIL datarowValidating is bullet proof
                        return;

                        //TODO : validate datarow but do not validate with the remote validators
                        var validationResult = jqGrid.validateDataRow(dataRow);

                        if (isNullOrUndefined(validationResult)) {
                            //do not prevent sending data to server because of internal error
                            jqGrid.updateDataOnRemoteWith(dataRow);
                            return;
                        }

                        if (validationResult.isValid === true) {
                            jqGrid.updateDataOnRemoteWith(dataRow);
                            return;
                        }

                        //validation failed : move datarow to sandbox
                        var updatedDataRow = jqGrid.updatedData.shift();
                        jqGrid.updatedDataWithValidationErrors.push(updatedDataRow);

                        //show validation errors in the grid
                        jqGrid.showValidationErrorsForDataRow(validationResult, updatedDataRow)

                        // continue remote operations
                        executeAsync(this, jqGrid.updateDataOnRemote, 0);
  
                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.deleteDataOnRemote = function () {
                    try {

                        if (jqGrid.hasNoRemoteOperationPending()) {
                            var eventArgs = {};
                            onDataInsertedUpdatedDeletedOnRemote(vpGrid, eventArgs);
                        }

                        if (isNullOrUndefinedOrEmpty(jqGrid.deletedData)) {
                            // there is nothing to do
                            return;
                        }

                        var dataRow = jqGrid.deletedData[0];
                        jqGrid.deleteDataOnRemoteWith(dataRow);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.updateInsertDeleteDataOnRemote = function () {
                    /// <signature>
                    /// <summary>Perform the CRUD operation from the jqGrid.updatedData/deletedData/insertedData arrays
                    ///   This method should be called only when the vpGrid option enableAutomaticPropagationOfUpdateInsertDeleteOperations is set to false.
                    ///   In other words this method should be called only when the grid was offline and is now online.
                    ///</summary>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (jqGrid.hasNoRemoteOperationPending()) {
                            var eventArgs = {};
                            onDataInsertedUpdatedDeletedOnRemote(vpGrid, eventArgs);
                            return;
                        }

                        if (jqGrid.hasRemoteDeleteOperationPending()) {
                            jqGrid.deleteDataOnRemote();
                        }
                        
                        if (jqGrid.hasRemoteInsertOperationPending()) {
                            jqGrid.insertDataOnRemote();
                        }

                        if (jqGrid.hasRemoteUpdateOperationPending()) {
                            jqGrid.updateDataOnRemote();
                        }
                        

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                jqGrid.insertDataOnRemoteWith = function (dataRow) {
                    /// <signature>
                    /// <summary>Trigger an ajax operation to send input data for insertion in remote database.</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        //step 0 : show qTip2 dialog
                        //showLoadingMessage();

                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertDataOnRemoteWith",
                                message: "Input data is null or empty : '" + dataRow + "'"
                            });
                            return;
                        }

                        if (dataRow.ajaxErrors && dataRow.ajaxErrors > 3) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertDataOnRemoteWith",
                                message: "Two many errors with server. All insert operations are canceled.",
                                info: "Check the urls set in the options passed to the vpGrid.init method. Check also if the server is up and running."
                            });
                            return;
                        }

                        //Raise event onInsertingDataOnRemote
                        var eventArgs = {
                            data: dataRow,
                            cancel: false,
                            cancelReason: ""
                        };

                        onInsertingDataOnRemote(vpGrid, eventArgs);

                        if (eventArgs.cancel === true) {
                            //TODO : log
                            var insertedDataRow = jqGrid.insertedData.shift();
                            // continue remote operations
                            jqGrid.insertDataOnRemote();
                            return;
                        }

                        var ajaxOptions = {
                            cache: false,
                            type: "GET",
                            dataType: "json",
                            success: function (response) {
                                try {
                                    jqGrid.loadInsertedDataFromWebResponse(response, dataRow);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            },
                            complete: function (xhr, textStatus) {
                                try {
                                    //TODO : remove the qtip2 message
                                    if (xhr && xhr.status !== 200) {
                                        dataRow.ajaxErrors = dataRow.ajaxErrors || 0;
                                        dataRow.ajaxErrors += 1;
                                    }

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                                finally {
                                    // continue remote operations
                                    jqGrid.insertDataOnRemote();
                                }
                            }
                        };

                        //get url to be requested
                        var crudOperations = vpGrid.options.crudOptions;
                        if (isNullOrUndefinedOrEmpty(crudOperations)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertDataOnRemoteWith",
                                message: "CRUD operations are not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(crudOperations.insert)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertDataOnRemoteWith",
                                message: "CRUD operation Insert is not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        var requestUrl = crudOperations.insert;
                        ajaxOptions.url = requestUrl;

                        ajaxOptions.data = dataRow;

                        $.extend(ajaxOptions, vpGridAjaxOptions);

                        //TODO : raise event to enable listeners inspect and/or modify ajaxOptions

                        $.ajax(ajaxOptions);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.updateDataOnRemoteWith = function (dataRow) {
                    /// <signature>
                    /// <summary>Trigger an ajax operation to send input data for update in remote database.</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        //step 0 : show qTip2 dialog
                        //showLoadingMessage();

                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataOnRemoteWith",
                                message: "Input data is null or empty : '" + dataRow + "'"
                            });
                            return;
                        }

                        if (dataRow.ajaxErrors && dataRow.ajaxErrors > 3 ) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataOnRemoteWith",
                                message: "Two many errors with server. All update operations are canceled.",
                                info : "Check the urls set in the options passed to the vpGrid.init method. Check also if the server is up and running."
                            });
                            return;
                        }

                        //Raise event onInsertingDataOnRemote
                        var eventArgs = {
                            data: dataRow,
                            cancel: false,
                            cancelReason: ""
                        };

                        onUpdatingDataOnRemote(vpGrid, eventArgs);

                        if (eventArgs.cancel === true) {
                            //TODO : log
                            var updatedDataRow = jqGrid.updatedData.shift();
                            // continue remote operations
                            jqGrid.updateDataOnRemote();
                            return;
                        }

                        var ajaxOptions = {
                            cache: false,
                            type: "GET",
                            dataType: "json",
                            success: function (response) {
                                try {
                                    jqGrid.loadUpdatedDataFromWebResponse(response, dataRow);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            },
                            complete: function (xhr, textStatus) {
                                try {
                                    //TODO : remove the qtip2 message
                                    
                                    if (xhr && xhr.status !== 200) {
                                        dataRow.ajaxErrors = dataRow.ajaxErrors || 0;
                                        dataRow.ajaxErrors += 1;
                                    }

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                                finally {
                                    // continue remote operations
                                    jqGrid.updateDataOnRemote();
                                }
                            }
                        };

                        //get url to be requested
                        var crudOperations = vpGrid.options.crudOptions;
                        if (isNullOrUndefinedOrEmpty(crudOperations)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataOnRemoteWith",
                                message: "CRUD operations are not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(crudOperations.update)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataOnRemoteWith",
                                message: "CRUD operation Update is not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        var requestUrl = crudOperations.update;

                        //check for custom crud url
                        if (dataRow.crudKey) {
                            var propertyName = dataRow.crudKey;

                            if (isNullOrUndefinedOrEmpty(crudOperations[propertyName])) {
                                vpGrid.logError({
                                    functionName: "jqGrid.updateDataOnRemoteWith",
                                    message: "CRUD operation Update with key : '" + dataRow.crudKey + "' is not defined in the vpGrid Options object. Data cannot be sent to server."
                                });
                                return;
                            }
                            var customUrl = crudOperations[propertyName];
                            requestUrl = customUrl;
                        }

                        ajaxOptions.url = requestUrl;

                        ajaxOptions.data = dataRow;

                        $.extend(ajaxOptions, vpGridAjaxOptions);

                        //TODO : raise event to enable listeners inspect and/or modify ajaxOptions

                        $.ajax(ajaxOptions);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.deleteDataOnRemoteWith = function (dataRow) {
                    /// <signature>
                    /// <summary>Trigger an ajax operation to send input data for update in remote database.</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        //step 0 : show qTip2 dialog
                        //showLoadingMessage();

                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.deleteDataOnRemoteWith",
                                message: "Input data is null or empty : '" + dataRow + "'"
                            });
                            return;
                        }

                        if (dataRow.ajaxErrors && dataRow.ajaxErrors > 3) {
                            vpGrid.logError({
                                functionName: "jqGrid.deleteDataOnRemoteWith",
                                message: "Two many errors with server. All delete operations are canceled.",
                                info: "Check the urls set in the options passed to the vpGrid.init method. Check also if the server is up and running."
                            });
                            return;
                        }

                        //Raise event onInsertingDataOnRemote
                        var eventArgs = {
                            data: dataRow,
                            cancel: false,
                            cancelReason: ""
                        };

                        onDeletingDataOnRemote(vpGrid, eventArgs);

                        if (eventArgs.cancel === true) {
                            //TODO : log
                            var deletedDataRow = jqGrid.deletedData.shift();
                            // continue remote operations
                            jqGrid.deleteDataOnRemote();
                            return;
                        }

                        var ajaxOptions = {
                            cache: false,
                            type: "GET",
                            dataType: "json",
                            success: function (response) {
                                try {
                                    jqGrid.loadDeletedDataFromWebResponse(response, dataRow);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            },
                            complete: function (xhr, textStatus) {
                                try {
                                    //TODO : remove the qtip2 message
                                    if (xhr && xhr.status !== 200) {
                                        dataRow.ajaxErrors = dataRow.ajaxErrors || 0;
                                        dataRow.ajaxErrors += 1;
                                    }

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                                finally {
                                    // continue remote operations
                                    jqGrid.deleteDataOnRemote();
                                }
                            }
                        };

                        //get url to be requested
                        var crudOperations = vpGrid.options.crudOptions;
                        if (isNullOrUndefinedOrEmpty(crudOperations)) {
                            vpGrid.logError({
                                functionName: "jqGrid.deleteDataOnRemoteWith",
                                message: "CRUD operations are not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(crudOperations['delete'])) {
                            vpGrid.logError({
                                functionName: "jqGrid.deleteDataOnRemoteWith",
                                message: "CRUD operation Delete is not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        var requestUrl = crudOperations['delete'];
                        ajaxOptions.url = requestUrl;

                        ajaxOptions.data = dataRow;

                        $.extend(ajaxOptions, vpGridAjaxOptions);

                        //TODO : raise event to enable listeners inspect and/or modify ajaxOptions

                        $.ajax(ajaxOptions);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.reloadDataRowFromRemote = function (dataRow) {
                    /// <signature>
                    /// <summary>Trigger an ajax operation to get the content of an existing data row updated by reloading data from server.</summary>
                    /// <param name="dataRow" type="Object">Literal object represeting a row already loaded in the grid.
                    ///                         This literal object contains column values. Each property of this object should match a column name.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        //TODO : show the visual clue
                        var keyColumnName = jqGrid.keyColumnName();
                        jqGrid.addClassForItemWithKey(dataRow[keyColumnName], 'vpgrid-refresh');

                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.reloadDataRowFromRemote",
                                message: "Input data is null or empty : '" + dataRow + "'"
                            });
                            return;
                        }

                        var ajaxOptions = {
                            cache: false,
                            type: "GET",
                            dataType: "json",
                            success: function (response) {
                                try {
                                    jqGrid.reloadDataRowFromWebResponse(response, dataRow);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            },
                            complete: function (xhr, textStatus) {
                                try {
                                    //TODO : remove the qtip2 message

                                    if (xhr && xhr.status !== 200) {
                                        dataRow.ajaxErrors = dataRow.ajaxErrors || 0;
                                        dataRow.ajaxErrors += 1;
                                    }

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                                finally {
                                    
                                }
                            }
                        };

                        //get url to be requested
                        var crudOperations = vpGrid.options.crudOptions;
                        if (isNullOrUndefinedOrEmpty(crudOperations)) {
                            vpGrid.logError({
                                functionName: "jqGrid.reloadDataRowFromRemote",
                                message: "CRUD operations are not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(crudOperations.readOne)) {
                            vpGrid.logError({
                                functionName: "jqGrid.reloadDataRowFromRemote",
                                message: "CRUD operation for reading one entity is not defined in the vpGrid Options object. Data cannot be refreshed from server.",
                                info: "Check for a property named 'readOne' in the crudOperations object passed to the vpGrid.init() method."
                            });
                            return;
                        }

                        var requestUrl = crudOperations.readOne;

                        ajaxOptions.url = requestUrl;

                        ajaxOptions.data = dataRow;

                        $.extend(ajaxOptions, vpGridAjaxOptions);

                        //TODO : raise event to enable listeners inspect and/or modify ajaxOptions

                        $.ajax(ajaxOptions);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.loadInsertedDataFromWebResponse = function (response, dataRow) {
                    /// <signature>
                    /// <summary>Process response data after insertion on remote server.
                    ///             The response object must have the following structure:
                    ///             {
                    ///                 "done" : true|false,
                    ///                 "reloadGrid" : true|false
                    ///                 "errorMessage" : "",
                    ///                 "data": 
                    ///                 {"remoteId" : "xxx"}
                    ///               -> remoteId = Name of the key column
                    ///               -> xxx = primary key set by remote server after inserting the data
                    ///             }
                    /// </summary>
                    /// <param name="response" type="Object">Literal object sent by remote server.</param>
                    /// <param name="dataRow" type="Object">Original data sent to server.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(response)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadInsertedDataFromWebResponse",
                                message: "Server response is null or undefined.",
                                info: "Check if the server is up and running. Check also if the crud options are correctly configured when calling vpGrid.init function."
                            });
                            return;
                        }

                        //TODO : raise event so that listeners can inspect and/or modify response object

                        if (response.done === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadInsertedDataFromWebResponse",
                                message: "An error has occured on server : " + response.errorMessage
                            });
                            jqGrid.showUINotification("", response.errorMessage, true);
                            return;
                        }

                        if (response.reloadGrid === true) {
                            // the all grid must be reloaded due to specific process on server that cannot be reflected simply on client-side
                            jqGrid.reloadData();
                            //TODO : check if other remote operations are pending -> if yes send error
                            //TODO : cancel all other pending remote operations
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(response.data)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadInsertedDataFromWebResponse",
                                message: "response.data object is null or undefined or empty.",
                                info: "response.data is forced to be an empty literal object."
                            });
                            response.data = {};
                        }

                        // update the entity key sent back by the server
                        var receivedData = response.data;
                        var keyColumnName = jqGrid.keyColumnName();
                        var remoteEntityId = receivedData[keyColumnName];
                        var clientEntityId = dataRow[keyColumnName];

                        var jqRow = jqGrid.getRowThatHoldsItemWithKey(clientEntityId);
                        if (jqRow.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadInsertedDataFromWebResponse",
                                message: "Cannot find the htlm table row for the item with key: '" + clientEntityId + "'"
                            });
                            return;
                        }

                        var rowid = jqRow[0].id;

                        jqGrid.setCell(rowid, keyColumnName, remoteEntityId);

                        //TODO : raise event so that listeners can inspect and/or modify response data

                        //raise event so that listeners can do post processing on inserted data
                        var eventArgs = {
                            sentData: dataRow,
                            receivedData: receivedData,
                            keyName: keyColumnName,
                            keyValue: remoteEntityId
                        };

                        onInsertedDataReceived(eventArgs);


                        //TODO : remove the visual clue
                        jqGrid.removeClassForItemWithKey(remoteEntityId, 'vpgrid-refresh');


                        //TODO : update any cell if needed
                        jqGrid.options.updateRowWithResponseData(receivedData);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                    finally {
                        var insertedDataRow = jqGrid.insertedData.shift();
                    }
                }

                jqGrid.loadUpdatedDataFromWebResponse = function (response, dataRow) {
                    /// <signature>
                    /// <summary>Process response data after update operation on remote server.
                    ///             The response object must have the following structure:
                    ///             {
                    ///                 "done" : true|false,
                    ///                 "reloadGrid" : true|false,
                    ///                 "removeItem" : true|false,
                    ///                 "removeItemMessage" : message to be displayed before removing the item from the grid
                    ///                 "errorMessage" : "",
                    ///                 "data": 
                    ///                 {"remoteId" : "xxx"}
                    ///               -> remoteId = Name of the key column
                    ///               
                    ///             }
                    /// </summary>
                    /// <param name="response" type="Object">Literal object sent by remote server after its update operation on dataRow.</param>
                    /// <param name="dataRow" type="Object">Original data sent to server.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(response)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadUpdatedDataFromWebResponse",
                                message: "Server response is null or undefined.",
                                info: "Check if the server is up and running. Check also if the crud options are correctly configured when calling vpGrid.init function."
                            });
                            return;
                        }

                        //TODO : raise event so that listeners can inspect and/or modify response object

                        if (response.done === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadUpdatedDataFromWebResponse",
                                message: "An eror has occured on server : " + response.message
                            });
                            return;
                        }

                        if (response.reloadGrid === true) {
                            // the all grid must be reloaded due to specific process on server that cannot be reflected simply on client-side
                            jqGrid.reloadData();
                            //TODO : check if other remote operations are pending -> if yes send error
                            //TODO : cancel all other pending remote operations
                            return;
                        }

                        


                        if (isNullOrUndefinedOrEmpty(response.data)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadUpdatedDataFromWebResponse",
                                message: "response.data object is null or undefined or empty.",
                                info: "response.data is forced to be an empty literal object."
                            });
                            response.data = {};
                        }

                        var receivedData = response.data;
                        var receivedDataArray = [];
                        receivedDataArray.push(receivedData);

                        //raise event onDataReceived
                        var eventArgs = {
                            data: receivedDataArray
                        }
                        onDataReceived(eventArgs);
                        var receivedData2 = eventArgs.data[0];

                        
                        //raise event onUpdatedDataReceived so that listeners can do post processing on updated data
                        var keyColumnName = jqGrid.keyColumnName();
                        var currentRowId = dataRow[keyColumnName];
                        var eventArgs2 = {
                            sentData: dataRow,
                            receivedData: receivedData2,
                            keyName: keyColumnName,
                            keyValue: currentRowId
                        }
                        onUpdatedDataReceived(eventArgs2);


                        //TODO : remove the visual clue
                        jqGrid.removeClassForItemWithKey(dataRow[keyColumnName], 'vpgrid-refresh');


                        //TODO : update any cell if needed
                        jqGrid.options.updateRowWithResponseData(receivedData2);

                        if (response.removeItem === true) {
                            //the updated item must be removed from the grid due to business conditions met on the server
                            //TODO : factorize these two lines
                            var keyColumnName = jqGrid.keyColumnName();
                            var remoteId = dataRow[keyColumnName];
                            jqGrid.removeItemWithKey(remoteId);
                            return;
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                    finally {
                        var updatedDataRow = jqGrid.updatedData.shift();
                    }
                }

                jqGrid.loadDeletedDataFromWebResponse = function (response, dataRow) {
                    /// <signature>
                    /// <summary>Process response data after Delete operation on remote server.
                    ///             The response object must have the following structure:
                    ///             {
                    ///                 "done" : true|false,
                    ///                 "reloadGrid" : true|false
                    ///                 "errorMessage" : "",
                    ///                 "data": 
                    ///                 {"remoteId" : "xxx"}
                    ///               -> remoteId = Name of the key column
                    ///               -> primary key of the deleted row on server
                    ///               
                    ///             }
                    /// </summary>
                    /// <param name="response" type="Object">Literal object sent by remote server after its update operation on dataRow.</param>
                    /// <param name="dataRow" type="Object">Original data sent to server.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(response)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadDeletedDataFromWebResponse",
                                message: "Server response is null or undefined.",
                                info: "Check if the server is up and running. Check also if the crud options are correctly configured when calling vpGrid.init function."
                            });
                            return;
                        }

                        //TODO : raise event so that listeners can inspect and/or modify response object

                        if (response.done === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadDeletedDataFromWebResponse",
                                message: "An error has occured on server : " + response.message
                            });
                            return;
                        }

                        if (response.reloadGrid === true) {
                            // the all grid must be reloaded due to specific process on server that cannot be reflected simply on client-side
                            jqGrid.reloadData();
                            //TODO : check if other remote operations are pending -> if yes send error
                            //TODO : cancel all other pending remote operations
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(response.data)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadDeletedDataFromWebResponse",
                                message: "response.data object is null or undefined or empty.",
                                info: "response.data is forced to be an empty literal object."
                            });
                            response.data = {};
                        }

                        //raise event so that listeners can inspect and/or modify response data

                        var receivedData = response.data;
                        var keyColumnName = jqGrid.keyColumnName();
                        var currentRowId = dataRow[keyColumnName];

                        //TODO : update any cell if needed
                        //jqGrid.setCell(currentRowId, keyColumnName, newRowId);

                        

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                    finally {
                        var deletedDataRow = jqGrid.deletedData.shift();
                    }
                }


                jqGrid.removeItemWithKey = function (itemKey) {
                    /// <signature>
                    /// <summary>Remove from the UI the item identified by its key itemKey. 
                    /// </summary>
                    /// <param name="itemKey" type="String">Entity key of the item</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(itemKey)) {
                            vpGrid.logError({
                                functionName: "jqGrid.removeItemWithKey",
                                message: "Item cannot be removed because its entity key is not valid: '" + itemKey + "'"
                            });
                        }

                        var jqRow = jqGrid.getRowThatHoldsItemWithKey(itemKey);
                        if (jqRow.notFound()) {
                            //TODO : log
                            return;
                        }

                        var rowid = jqRow[0].id;
                        //execute async to free the UI thread
                        var firstVisibleColumnName = jqGrid.firstVisibleColumnName();
                        var jqCell = jqGrid.cell(rowid, firstVisibleColumnName);
                        vpGrid.showUINotificationAtElement(jqCell[0], "", vpGrid.UIString.rowWillDisappearDueToServerFiltering, {
                            hide: {
                                event: false,
                                inactive: 3000
                            }
                        });
                        executeAsync(this, function () {
                            try {
                                jqGrid.removeRow(rowid);
                                jqGrid.options.gridComplete();

                            } catch (e) {
                                vpGrid.logException(e);
                            }

                        }, 3000, "removeItemWithKey");
                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }


                jqGrid.reloadDataRowFromWebResponse = function (response, dataRow) {
                    /// <signature>
                    /// <summary>Process response data after reading one item represented by input dataRow on remote server.
                    ///             The response object must have the following structure:
                    ///             {
                    ///                 "done" : true|false,
                    ///                 "reloadGrid" : true|false
                    ///                 "removeItem" : true|false,
                    ///                 "removeItemMessage" : message to be displayed before removing the item from the grid
                    ///                 "errorMessage" : "",
                    ///                 "data": 
                    ///                 {"remoteId" : "xxx"}
                    ///               -> remoteId = Name of the key column
                    ///               
                    ///             }
                    /// </summary>
                    /// <param name="response" type="Object">Literal object sent by remote server </param>
                    /// <param name="dataRow" type="Object">Original data sent to server.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(response)) {
                            vpGrid.logError({
                                functionName: "jqGrid.reloadDataRowFromWebResponse",
                                message: "Server response is null or undefined.",
                                info: "Check if the server is up and running. Check also if the crud options are correctly configured when calling vpGrid.init function."
                            });
                            return;
                        }

                        //TODO : raise event so that listeners can inspect and/or modify response object

                        if (response.done === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.reloadDataRowFromWebResponse",
                                message: "An eror has occured on server : " + response.message
                            });
                            return;
                        }

                        if (response.reloadGrid === true) {
                            // the all grid must be reloaded due to specific process on server that cannot be reflected simply on client-side
                            jqGrid.reloadData();
                            //TODO : check if other remote operations are pending -> if yes send error
                            //TODO : cancel all other pending remote operations
                            return;
                        }


                        if (isNullOrUndefinedOrEmpty(response.data)) {
                            vpGrid.logError({
                                functionName: "jqGrid.reloadDataRowFromWebResponse",
                                message: "response.data object is null or undefined or empty.",
                                info: "response.data is forced to be an empty literal object."
                            });
                            response.data = {};
                        }

                        

                        //TODO : raise event onDataReceived
                        var receivedData = response.data;

                        //raise event so that listeners can do post processing on updated data
                        var keyColumnName = jqGrid.keyColumnName();
                        var currentRowId = dataRow[keyColumnName];
                        var eventArgs = {
                            sentData: dataRow,
                            receivedData: receivedData,
                            keyName: keyColumnName,
                            keyValue: currentRowId
                        }
                        onUpdatedDataReceived(eventArgs);

                        //TODO : remove the visual clue
                        jqGrid.removeClassForItemWithKey(dataRow[keyColumnName], 'vpgrid-refresh');


                        //TODO : update any cell if needed
                        jqGrid.options.updateRowWithResponseData(receivedData);

                        if (response.removeItem === true) {
                            //the updated item must be removed from the grid due to business conditions met on the server
                            //TODO : factorize these two lines
                            var keyColumnName = jqGrid.keyColumnName();
                            var remoteId = dataRow[keyColumnName];
                            jqGrid.removeItemWithKey(remoteId);
                            return;
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                    finally {
                        
                    }
                }

                jqGrid.hasRemoteOperationPending = function() {
                    try {
                        if (jqGrid.insertedData.length > 0) {
                            return true;
                        }

                        if (jqGrid.insertedDataWithValidationErrors.length > 0) {
                            return true;
                        }

                        if (jqGrid.updatedData.length > 0) {
                            return true;
                        }

                        if (jqGrid.updatedDataWithValidationErrors.length > 0) {
                            return true;
                        }

                        if (jqGrid.deletedData.length > 0) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.hasNoRemoteOperationPending = function () {
                    return jqGrid.hasRemoteOperationPending() === false;
                }

                jqGrid.hasRemoteDeleteOperationPending = function () {
                    try {
                        
                        if (jqGrid.deletedData.length > 0) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }
                jqGrid.hasNoRemoteDeleteOperationPending = function () {
                    return jqGrid.hasRemoteDeleteOperationPending() === false;
                }

                jqGrid.hasRemoteInsertOperationPending = function () {
                    try {
                        if (jqGrid.insertedData.length > 0) {
                            return true;
                        }

                        if (jqGrid.insertedDataWithValidationErrors.length > 0) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }
                jqGrid.hasNoRemoteInsertOperationPending = function () {
                    return jqGrid.hasRemoteInsertOperationPending() === false;
                }

                jqGrid.hasRemoteUpdateOperationPending = function () {
                    try {
                        
                        if (jqGrid.updatedData.length > 0) {
                            return true;
                        }

                        if (jqGrid.updatedDataWithValidationErrors.length > 0) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }
                jqGrid.hasNoRemoteUpdateOperationPending = function () {
                    return jqGrid.hasRemoteUpdateOperationPending() === false;
                }

                jqGrid.onBeforeUnload = function (event) {
                    /// <signature>
                    /// <summary>Event handler that prevents closing window if a remote operation is pending.</summary>
                    /// <param name="event" type="Object">Literal object passed by the window.onbeforeunload event</param>
                    /// <returns type="String">Returns a non empty message if CRUD operations are not completed.</returns>
                    /// </signature>
                    try {

                        var eventArgs = {
                            data: jqGrid.getData(),
                            cancel: false,
                            cancelReason: ""
                        };

                        if (jqGrid.hasRemoteOperationPending()) {
                            eventArgs.cancel = true;
                            eventArgs.cancelReason = vpGrid.UIString.pendingOperationOnRemoteServer;
                        }

                        onWindowClosing(vpGrid, eventArgs);

                        if (eventArgs.cancel === true ) {
                            return eventArgs.cancelReason;
                        }

                        return;
                        
                    } catch (e) {
                        vpGrid.logException(e);
                        return ;
                    }
                }

                jqGrid.insertNewRowAfterSelected = function (dataRow) {
                    /// <signature>
                    /// <summary>Insert a new row in the grid after the currently selected row.</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRowAfterSelected",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                        var jqGridHost = jqGrid.host();
                        var inserted = jqGridHost.jqGrid('addRowData', undefined, dataRow, 'after', jqGrid.currentRowId);

                        if (inserted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRowAfterSelected",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }

                        jqGrid.totalItemCount += 1;
                        //set number of rows in jqGrid
                        var gridOptions = {
                            rowNum: jqGrid.totalItemCount
                        };
                        jqGridHost.jqGrid('setGridParam', gridOptions);


                        //TODO : refresh the grid with current filters

                        //TODO : update the inserted data array

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.insertInlineSummaryRowAfterSelected = function (dataRow) {
                    /// <signature>
                    /// <summary>Insert a new summary row in the grid after the currently selected row.</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowAfterSelected",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                        var jqGridHost = jqGrid.host();
                        var rowid = 'summaryAfter' + jqGrid.currentRowId;
                        var inserted = jqGridHost.jqGrid('addInlineSummaryRowData', rowid, dataRow, 'after', jqGrid.currentRowId);

                        if (inserted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowAfterSelected",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }


                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.insertInlineSummaryRowAfter = function (rowid, dataRow, summaryRowidPrefix) {
                    /// <signature>
                    /// <summary>Insert a new summary row in the grid after the row with id rowid.</summary>
                    /// <param name="rowid" type="String">Dom id of the row after which to insert the summary row.</param>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be created. 
                    ///             If not defined this parameter will receive the value : 'summaryAfter'
                    ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
                    ///             The data attribute "data-vpgrid-summary-id" will be automatically injected on the summary row :
                    ///                     data-vpgrid-summary-id=summaryRowidPrefix
                    ///                     -> this will be possible to create a summary row in the footer that is the sum of only summary rows with that data tag value
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowAfter",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                        var summaryRowid = 'summaryAfter' + rowid;

                        if (isNotNullOrUndefinedOrEmpty(summaryRowidPrefix)) {
                            summaryRowid = summaryRowidPrefix  + rowid;
                        }

                        var jqGridHost = jqGrid.host();
                        var inserted = jqGridHost.jqGrid('addInlineSummaryRowData', summaryRowid, dataRow, 'after', rowid);

                        if (inserted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowAfter",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }

                        //flag rowid as having a summary row after itself
                        jqGrid.row(rowid).addClass('has-summary-row-after');

                        // add the data-tag 
                        jqGrid.row(summaryRowid).attr('data-vpgrid-summary-id', summaryRowidPrefix);
                        jqGrid.row(summaryRowid).attr('data-vpgrid-summary-for', rowid);

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.updateInlineSummaryRowAfter = function (rowid, dataRow, summaryRowidPrefix) {
                    /// <signature>
                    /// <summary>Update an existing inline summary row in the grid after the row with id rowid.</summary>
                    /// <param name="rowid" type="String">Dom id of the row after which to update the summary row.</param>
                    /// <param name="dataRow" type="Object">Literal object containing column values to show in the summary row. Each property of this object must match a column name.</param>
                    /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be updated. 
                    ///             If not defined this parameter will receive the value : 'summaryAfter'
                    ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
                    ///             The data attribute "data-vpgrid-summary-id" will be automatically injected on the summary row :
                    ///                     data-vpgrid-summary-id=summaryRowidPrefix
                    ///                     -> this will be possible to create a summary row in the footer that is the sum of only summary rows with that data tag value
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateInlineSummaryRowAfter",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                        var summaryRowid = 'summaryAfter' + rowid;

                        if (isNotNullOrUndefinedOrEmpty(summaryRowidPrefix)) {
                            summaryRowid = summaryRowidPrefix + rowid;
                        }

                        var jqGridHost = jqGrid.host();
                        var updated = jqGridHost.jqGrid('setInlineSummaryRowData', summaryRowid, dataRow);

                        if (updated === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateInlineSummaryRowAfter",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }

                        //check if cell content is out of range
                        jqGrid.options.afterUpdateInlineSummaryRow(rowid, summaryRowid, dataRow)
                        

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.insertInlineSummaryRowBefore = function (rowid, dataRow, summaryRowidPrefix) {
                    /// <signature>
                    /// <summary>Insert a new summary row in the grid before the row with id rowid.</summary>
                    /// <param name="rowid" type="String">Dom id of the row before which to insert the summary row.</param>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be created. 
                    ///             If not defined this parameter will receive the value : 'summaryBefore'
                    ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
                    ///             The data attribute "data-vpgrid-summary-id" will be automatically injected on the summary row :
                    ///                     data-vpgrid-summary-id=summaryRowidPrefix
                    ///                     -> this will be possible to create a summary row in the footer that is the sum of only summary rows with that data tag value
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowBefore",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                       
                        var summaryRowid = 'summaryBefore' + rowid;
                        if (isNotNullOrUndefinedOrEmpty(summaryRowidPrefix)) {
                            summaryRowid = summaryRowidPrefix + rowid;
                        }

                        var jqGridHost = jqGrid.host();
                        var inserted = jqGridHost.jqGrid('addInlineSummaryRowData', summaryRowid, dataRow, 'before', rowid);

                        if (inserted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowBefore",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }

                        //flag rowid as having a summary row after itself
                        jqGrid.row(summaryRowid).addClass('is-summary-row-before');

                        // add the data-tag 
                        jqGrid.row(summaryRowid).attr('data-vpgrid-summary-id', summaryRowidPrefix);
                        jqGrid.row(summaryRowid).attr('data-vpgrid-summary-for', rowid);


                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.updateInlineSummaryRowBefore = function (rowid, dataRow, summaryRowidPrefix) {
                    /// <signature>
                    /// <summary>Update an existing inline summary row in the grid before the row with id rowid.</summary>
                    /// <param name="rowid" type="String">Dom id of the row before which to update the summary row.</param>
                    /// <param name="dataRow" type="Object">Literal object containing column values to show in the summary row. Each property of this object must match a column name.</param>
                    /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be updated. 
                    ///             If not defined this parameter will receive the value : 'summaryBefore'
                    ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
                    ///             The data attribute "data-vpgrid-summary-id" will be automatically injected on the summary row :
                    ///                     data-vpgrid-summary-id=summaryRowidPrefix
                    ///                     -> this will be possible to create a summary row in the footer that is the sum of only summary rows with that data tag value
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateInlineSummaryRowBefore",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                        var summaryRowid = 'summaryBefore' + rowid;

                        if (isNotNullOrUndefinedOrEmpty(summaryRowidPrefix)) {
                            summaryRowid = summaryRowidPrefix + rowid;
                        }

                        var jqGridHost = jqGrid.host();
                        var updated = jqGridHost.jqGrid('setInlineSummaryRowData', summaryRowid, dataRow);

                        if (updated === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateInlineSummaryRowBefore",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }

                        //check if cell content is out of range
                        jqGrid.options.afterUpdateInlineSummaryRow(rowid, summaryRowid, dataRow)


                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.removeRow = function (rowid) {
                    /// <signature>
                    /// <summary>Remove from the UI a row in the grid. 
                    /// </summary>
                    /// <param name="rowid" type="String">Dom id of the row to be removed from the grid.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(rowid)) {
                            vpGrid.logError({
                                functionName: "jqGrid.removeRow",
                                message: "Row cannot be removed because its DOM id is not valid: '" + rowid + "'"
                            });
                        }

                        //Delete inline summary rows if any
                        jqGrid.deleteInlineSummaryRowsForRow(rowid);

                        //var rowData = jqGrid.rowData(rowid);

                        var jqGridHost = jqGrid.host();
                        var deleted = jqGridHost.jqGrid('delRowData', rowid);

                        if (deleted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.removeRow",
                                message: "Row with id '" + rowid + "' cannot be removed by jqGrid"
                            });

                            return;
                        }

                        
                        //reset the current selected row
                        if (rowid === jqGrid.currentRowId) {
                            jqGrid.currentRowId = null;
                            jqGrid.lastSelectedCheckboxId = "";
                            jqGrid.currentSelectedCheckboxId = "";
                        }

                        // update number of rows in the grid
                        jqGrid.totalItemCount -= 1;
                        //set number of rows in jqGrid
                        var gridOptions = {
                            rowNum: jqGrid.totalItemCount
                        };
                        jqGridHost.jqGrid('setGridParam', gridOptions);

                        jqGrid.options.renderSummaryRows();

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }




                jqGrid.deleteRow = function (rowid) {
                    /// <signature>
                    /// <summary>Delete a row in the grid.</summary>
                    /// <param name="rowid" type="String">Dom id of the row to be deleted in the grid.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(rowid)) {
                            vpGrid.logError({
                                functionName: "jqGrid.deleteRow",
                                message: "Row cannot be removed because its DOM id is not valid: '" + rowid + "'"
                            });
                        }

                        var rowData = jqGrid.rowData(rowid);

                        var jqGridHost = jqGrid.host();
                        var deleted = jqGridHost.jqGrid('delRowData', rowid);

                        if (deleted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.deleteRow",
                                message: "Row with id '" + rowid + "' cannot be removed by jqGrid"
                            });

                            return;
                        }

                        //Delete inline summary rows if any
                        jqGrid.deleteInlineSummaryRowsForRow(rowid);

                        //reset the current selected row
                        if (rowid === jqGrid.currentRowId) {
                            jqGrid.currentRowId = null;
                            jqGrid.lastSelectedCheckboxId = "";
                            jqGrid.currentSelectedCheckboxId = "";
                        }
                        
                        // update number of rows in the grid
                        jqGrid.totalItemCount -= 1;
                        //set number of rows in jqGrid
                        var gridOptions = {
                            rowNum: jqGrid.totalItemCount
                        };
                        jqGridHost.jqGrid('setGridParam', gridOptions);

                        //TODO : refresh the grid with current filters


                        //update internal CRUD arrays 
                        jqGrid.updateDataWithDeletedRow(rowData);

                        if (vpGrid.options.enableAutomaticPropagationOfUpdateInsertDeleteOperations === true) {
                            //grid is online
                            jqGrid.updateInsertDeleteDataOnRemote();
                            return;
                        }
                        

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.deleteCurrentRow = function () {
                    /// <signature>
                    /// <summary>Delete the current selected row in the grid</summary>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        var rowid = jqGrid.currentRowId;
                        jqGrid.deleteRow(rowid);

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }


                jqGrid.updateDataWithDeletedRow = function (rowData) {
                    /// <signature>
                    /// <summary>Update the updatedData/deletedData/insertedData arrays that hold data for the CRUD operations management
                    ///   when input rowData is the data of an item just deleted in the UI by the user or by code (jqGrid.deleteRow).
                    ///   This method should be called only when the vpGrid option enableAutomaticPropagationOfUpdateInsertDeleteOperations is set to false.
                    ///   In other words this method should be called only when the grid is offline.
                    ///</summary>
                    /// <param name="rowData" type="Object">Literal object representing the deleted item in the grid.
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(rowData)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithDeletedRow",
                                message: "Input data is not valid: it is either null or undefined or empty."
                            });
                            return;
                        }

                        var keyName = JQGrid.keyColumnName();
                        if (isNullOrUndefinedOrEmpty(keyName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithDeletedRow",
                                message: "Key column not found. Input data is discarded and will not be sent to remote server.",
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnType + "=key'," + " must be defined int the column schema."
                            });
                            return;
                        }

                        if (rowData[keyName] === undefined) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithDeletedRow",
                                message: "Input data does not contain a property called '" + keyName + "'. Input data is discarded and will not be sent to remote server.",
                                info: "Check how input data is generated : '" + rowData.toString()+ "'" 
                            });
                            return;
                        }

                        var keyValue = rowData[keyName];
                        if (isNullOrUndefinedOrEmpty(keyValue)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithDeletedRow",
                                message: "Input contains a property called '" + keyName + "' but the value of this property is either null or undefined or empty : '" + keyValue + "'. Input data is discarded and will not be sent to remote server.",
                                info: "Check how input data is generated : '" + rowData.toString() + "'"
                            });
                            return;
                        }

                        if (jqGrid.updatedData.hasAnObjectWithPropertyAndValue(keyName,keyValue)) {
                            jqGrid.updatedData.removeAllObjectsWithPropertyAndValue(keyName,keyValue);
                        }

                        if (jqGrid.updatedDataWithValidationErrors.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            jqGrid.updatedDataWithValidationErrors.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                        }

                        if (jqGrid.insertedData.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            //row has been inserted on the client, so process the delete as a globally null operation
                            jqGrid.insertedData.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                            return;
                        }

                        if (jqGrid.insertedDataWithValidationErrors.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            //row has been inserted on the client but has validation errors, so process the delete as a globally null operation
                            jqGrid.insertedDataWithValidationErrors.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                            return;
                        }

                        //delete is done on a row sent by server
                        jqGrid.deletedData.push(rowData);


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.updateDataWithUpdatedRow = function (rowData) {
                    /// <signature>
                    /// <summary>Update the updatedData/deletedData/insertedData arrays that hold data for the CRUD operations management
                    ///   when input rowData is the data of an item just updated in the UI by the user or by code.
                    ///   This method should be called only when the vpGrid option enableAutomaticPropagationOfUpdateInsertDeleteOperations is set to false.
                    ///   In other words this method should be called only when the grid is offline.
                    ///</summary>
                    /// <param name="rowData" type="Object">Literal object representing the updated item in the grid.
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(rowData)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithUpdatedRow",
                                message: "Input data is not valid: it is either null or undefined or empty."
                            });
                            return;
                        }

                        var keyName = JQGrid.keyColumnName();
                        if (isNullOrUndefinedOrEmpty(keyName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithUpdatedRow",
                                message: "Key column not found. Input data is discarded and will not be sent to remote server.",
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnType + "=key'," + " must be defined int the column schema."
                            });
                            return;
                        }

                        if (rowData[keyName] === undefined) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithUpdatedRow",
                                message: "Input data does not contain a property called '" + keyName + "'. Input data is discarded and will not be sent to remote server.",
                                info: "Check how input data is generated : '" + rowData.toString() + "'"
                            });
                            return;
                        }

                        var keyValue = rowData[keyName];
                        if (isNullOrUndefinedOrEmpty(keyValue)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithUpdatedRow",
                                message: "Input contains a property called '" + keyName + "' but the value of this property is either null or undefined or empty : '" + keyValue + "'. Input data is discarded and will not be sent to remote server.",
                                info: "Check how input data is generated : '" + rowData.toString() + "'"
                            });
                            return;
                        }

                        if (jqGrid.deletedData.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithUpdatedRow",
                                message: "Input data was already deleted with the key : " + keyName + "='" + keyValue + "'. Previous deletes are kept but it could lead to a possible mistmatch on server side.",
                                info: "Check how input data is generated : '" + rowData.toString() + "'"
                            });
                            //jqGrid.deletedData.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                        }

                        if (jqGrid.insertedData.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            //row has been inserted on the client, so process the update as a new insert
                            jqGrid.insertedData.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                            jqGrid.insertedData.push(rowData);
                            return;
                        }

                        if (jqGrid.insertedDataWithValidationErrors.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            //row has been inserted on the client, has validation errors, so process the update as a new insert
                            jqGrid.insertedDataWithValidationErrors.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                            jqGrid.insertedData.push(rowData);
                            return;
                        }

                        //update is done on a row sent by server
                        if (jqGrid.updatedData.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            // do not keep every update because input rowData reflects all previous updates
                            jqGrid.updatedData.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                        }

                        if (jqGrid.updatedDataWithValidationErrors.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            // do not keep every update because input rowData reflects all previous updates
                            jqGrid.updatedDataWithValidationErrors.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                        }


                        jqGrid.updatedData.push(rowData);


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.updateDataWithInsertedRow = function (rowData) {
                    /// <signature>
                    /// <summary>Update the updatedData/deletedData/insertedData arrays that hold data for the CRUD operations management
                    ///   when input rowData is the data of an item just inserted in the UI by the user or by code.
                    ///   This method should be called only when the vpGrid option enableAutomaticPropagationOfUpdateInsertDeleteOperations is set to false.
                    ///   In other words this method should be called only when the grid is offline.
                    ///</summary>
                    /// <param name="rowData" type="Object">Literal object representing the inserted item in the grid.
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(rowData)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithInsertedRow",
                                message: "Input data is not valid: it is either null or undefined or empty."
                            });
                            return;
                        }

                        var keyName = JQGrid.keyColumnName();
                        if (isNullOrUndefinedOrEmpty(keyName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithInsertedRow",
                                message: "Key column not found. Input data is discarded and will not be sent to remote server.",
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnType + "=key'," + " must be defined int the column schema."
                            });
                            return;
                        }

                        if (rowData[keyName] === undefined) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithInsertedRow",
                                message: "Input data does not contain a property called '" + keyName + "'. Input data is discarded and will not be sent to remote server.",
                                info: "Check how input data is generated : '" + rowData.toString() + "'"
                            });
                            return;
                        }

                        var keyValue = rowData[keyName];
                        if (isNullOrUndefinedOrEmpty(keyValue)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithInsertedRow",
                                message: "Input contains a property called '" + keyName + "' but the value of this property is either null or undefined or empty : '" + keyValue + "'. Input data is discarded and will not be sent to remote server.",
                                info: "Check how input data is generated : '" + rowData.toString() + "'"
                            });
                            return;
                        }


                        if (jqGrid.deletedData.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithInsertedRow",
                                message: "Input data was already deleted with the key : " + keyName + "='" + keyValue + "'. Previous deletes are kept but it could lead to a possible mistmatch on server side.",
                                info: "Check how input data is generated : '" + rowData.toString() + "'"
                            });
                            //jqGrid.deletedData.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                        }


                        if (jqGrid.updatedData.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithInsertedRow",
                                message: "Input data was already updated with the key : " + keyName + "='" + keyValue + "'. Previous updates are all removed. This insert is processed as an update.",
                                info: "Check how input data is generated : '" + rowData.toString() + "'"
                            });
                            jqGrid.updatedData.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                            jqGrid.updatedData.push(rowData);
                            return;
                        }

                        if (jqGrid.updatedDataWithValidationErrors.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithInsertedRow",
                                message: "Input data was already updated  (with validation errors) with the key : " + keyName + "='" + keyValue + "'. Previous updates are all removed. This insert is processed as an update.",
                                info: "Check how input data is generated : '" + rowData.toString() + "'"
                            });
                            jqGrid.updatedDataWithValidationErrors.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                            jqGrid.updatedData.push(rowData);
                            return;
                        }

                        if (jqGrid.insertedData.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            //row has already been inserted on the client, so process the insert as a new insert
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithInsertedRow",
                                message: "Input data was already inserted with the key : " + keyName + "='" + keyValue + "'. Previous insert is replaced by this new insert.",
                                info: "Check how input data is generated : '" + rowData.toString() + "'"
                            });
                            jqGrid.insertedData.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                            jqGrid.insertedData.push(rowData);
                            return;
                        }

                        if (jqGrid.insertedDataWithValidationErrors.hasAnObjectWithPropertyAndValue(keyName, keyValue)) {
                            //row has already been inserted on the client but this row has validation errors, so process the insert as a new insert
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataWithInsertedRow",
                                message: "Input data was already inserted (with validation errors) with the key : " + keyName + "='" + keyValue + "'. Previous insert is replaced by this new insert.",
                                info: "Check how input data is generated : '" + rowData.toString() + "'"
                            });
                            jqGrid.insertedDataWithValidationErrors.removeAllObjectsWithPropertyAndValue(keyName, keyValue);
                            jqGrid.insertedData.push(rowData);
                            return;
                        }

                        
                        jqGrid.insertedData.push(rowData);


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }



                function buildColModels() {
                    try {
                        var jqGridSchema = tryFindCurrentGridSchema();

                        if (jqGridSchema.notFound()) {
                            //TODO : log
                            return;
                        }

                        var columsSelector = "tr[role=" + vpGrid.HtmlRoleAttribute.vpGridSchemaColumns + "] ";
                        columsSelector += "th";
                        var jqColumns = jqGridSchema.find(columsSelector);

                        if (jqColumns.notFound()) {
                            vpGrid.logError({
                                message: "Missing description of the excell grid columns. Please insert them in the Web page to activate the Excel grid."
                            });
                        }

                        //remove any header content for hidden columns
                        hiddenColumnsSelector = columsSelector + "[data-vpgrid-column-hidden=true]";
                        $(hiddenColumnsSelector).html("");

                        var colNames = [];
                        var colModel = [];
                        
                        var columnsCount = jqColumns.length;
                        for (var i = 0; i < columnsCount; i++) {
                            var jqColumn = $(jqColumns[i]);
                            var colSchema = {};
                            // get the column title
                            colSchema.title = jqColumn.html();

                            //get the column name
                            colSchema.name = jqColumn.attr(vpGrid.HtmlDataTag.ColumnName);
                            colSchema.index = colSchema.name;
                            if (jqGrid.isNotValidColumnName(colSchema.name)) {
                                vpGrid.logError({
                                    message: "Column name is not valid.",
                                    info: "You must give another name for the column : '" + outerHtml(jqColumn[0]) + "'"
                                });
                            }

                            //check for another column with same name
                            if (colModel.hasAnObjectWithPropertyAndValue("name", colSchema.name)) {
                                vpGrid.logError({
                                    message: "Column name already exist.",
                                    info: "You must give another name for the column : '" + outerHtml(jqColumn[0]) + "'"
                                });
                            }

                            //get the column width
                            var minColWidth = jqGrid.options.minColWidth;
                            colSchema.width = jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnWidth, minColWidth)
                            colSchema.fixed = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnFixedWidth, false)

                            //enforce column min width
                            if (colSchema.width < minColWidth && colSchema.fixed === false) {
                                colSchema.width = minColWidth;
                            }

                            //get the column hidden attribute
                            colSchema.hidden = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnHidden, false);
                            if (colSchema.hidden === true) {
                                colSchema.width = 0;
                            }

                            //get the column frozen attribute
                            colSchema.frozen = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnFrozen, false);
                            if (colSchema.frozen) {
                                jqGrid.hasFrozenColumns = true;
                            }

                            //get the column sortable attribute
                            colSchema.sortable = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnSortable, true);


                            //get the column editable attribute
                            colSchema.editable = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnEditable, false);
                            if (colSchema.hidden === true && colSchema.editable === true) {
                                vpGrid.logError({
                                    message: "Column '" + colSchema.name + "' is both hidden and editable. This column is forced to be uneditable",
                                    info: "Check the configuration of the column : '" + outerHtml(jqColumn[0]) + "'"
                                });
                                colSchema.editable = false;
                            }

                            //get the column edittype attribute
                            // warning : edittype may be overwritten below on specific column Type
                            colSchema.edittype = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnEditType, "text");
                            if (colSchema.edittype === "select") {
                                // create a custom property to flag this column as a select type
                                // this flag will be used to dynamically inject select options in cell editing
                                colSchema.isSelect = true;

                                //read the default key/values for the select options
                                var selectOptionsValue = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.SelectOptions, null);
                                if (selectOptionsValue != null) {
                                    colSchema.editoptions = colModel.editoptions || {};
                                    colSchema.editoptions.value = selectOptionsValue;
                                    colSchema.editoptions.defaultValue = selectOptionsValue;
                                    colSchema.hasDefaultSelectOptions = true;
                                }
                               
                            } // end if (colSchema.edittype === "select")

                            if (colSchema.edittype === "autocomplete") {
                                // create a custom property to flag this column as an input textbox with autocomplete
                                // this flag will be used to dynamically inject autocomplete plug-in in cell editing
                                colSchema.edittype = "text";
                                colSchema.isAutocomplete = true;
                            }

                            //setup default search options on columns (used by filterToolbar)
                            colSchema.stype = 'text';
                            colSchema.searchoptions = { sopt: ['cn', 'eq', 'bw', 'bn', 'nc', 'ew', 'en'] };
                            colSchema.search = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnFilterable, true);
                            
                            //get the column align attribute
                            colSchema.align = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnAlign, "left");

                            //get the column type attribute
                            var colType = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnType, "string");

                            if (jqGrid.isNotValidColumnType(colType)) {
                                vpGrid.logError({
                                    message: "Column type '" + colType + "' is not valid.",
                                    info: "You must give another type for the column : '" + outerHtml(jqColumn[0]) + "'"
                                });
                            }
                            if (colType === "string") {
                                colSchema.isString = true;
                            }

                            if (colType === "checkbox") {
                                colSchema.formatter = "checkbox";
                                colSchema.edittype = "checkbox";
                                // create a custom property to flag this column as checkbox type
                                // this flag will be used to dynamically inject xxx in cell editing
                                colSchema.isCheckbox = true;
                            }

                            if (colType === "note") {
                                colSchema.edittype = "textarea";
                                colSchema.editoptions = { rows: "2", cols: "15" };
                                // create a custom property to flag this column as note type
                                // this flag will be used to dynamically inject xxx in cell editing
                                colSchema.isNote = true;
                            }

                            if (colType === "currency") {
                                colSchema.formatter = "currency";
                                colSchema.formatoptions = jqGrid.defaultCurrencyFormatOptions();

                                colSchema.isCurrency = true;
                                colSchema.editrules = {
                                    number: true,
                                    minValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMinValue, null),
                                    maxValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMaxValue, null)
                                };
                            }

                            if (colType === "int") {
                                colSchema.formatter = "integer";
                                colSchema.formatoptions = jqGrid.defaultIntegerFormatOptions();

                                colSchema.isInteger = true;
                                colSchema.editrules = {
                                    integer: true,
                                    minValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMinValue, null),
                                    maxValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMaxValue, null)
                                };
                            }

                            if (colType === "number") {
                                colSchema.formatter = "number";
                                colSchema.formatoptions = jqGrid.defaultNumberFormatOptions();

                                colSchema.isNumber = true;
                                colSchema.editrules = {
                                    number: true,
                                    minValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMinValue, null),
                                    maxValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMaxValue, null)
                                };
                            }

                            if (colType === "link") {
                                colSchema.formatter = jqGrid.linkFormatter;
                                colSchema.unformat = jqGrid.linkUnformatter;
                                colSchema.formatoptions = { target: '_vpTab' };
                                colSchema.isLink = true;
                            }

                            if (colType === "date") {
                                colSchema.formatter = "date";
                                colSchema.formatoptions = jqGrid.defaultDateFormatOptions();
                                colSchema.sorttype = "date";
                                // create a custom property to flag this column as date type
                                // this flag will be used to dynamically inject datepicker in cell editing
                                colSchema.isDate = true;
                                colSchema.editrules = {
                                    date: true
                                    
                                };
                            }

                            if (colType === "year") {
                                // create a custom property to flag this column as date type
                                // this flag will be used to dynamically inject select element in cell editing
                                colSchema.isYear = true;
                                colSchema.editrules = {
                                    integer: true,
                                    minValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMinValue, null),
                                    maxValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMaxValue, null)
                                };
                            }

                            if (colType === "image") {
                                colSchema.formatter = jqGrid.imageFormatter;
                                colSchema.unformat = jqGrid.imageUnformatter;
                                colSchema.isImage = true;
                            }

                            if (colType === "key") {
                                colSchema.isKey = true;
                                colSchema.key = false; // jqGrid generates its own id for each table row
                            }

                            //check for unique value constraint
                            colSchema.hasUniqueValueConstraint = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnUniqueValueConstraint, false);
                            
                            var actionType = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnActionType, "");
                            if (colType === "action") {
                                //fix the width of the action
                                colSchema.fixed = true;
                                colSchema.search = false;
                                //force width value (do not take minColWidth option if a width value is set in the html column schema)
                                colSchema.width = jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnWidth, minColWidth)
                                colSchema.isAction = true;
                            }
                            if (colType === "action" && actionType === "deleteItem") {
                                colSchema.formatter = jqGrid.deleteItemFormatter;
                                colSchema.unformat = jqGrid.deleteItemUnformatter;
                                colSchema.isDeleteAction = true;
                                
                            }

                            if (colType === "actionValidator") {
                                //fix the width of the action
                                colSchema.fixed = true;
                                colSchema.search = false;
                                //force width value (do not take minColWidth option if a width value is set in the html column schema)
                                colSchema.width = jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnWidth, minColWidth)
                                colSchema.isActionValidator = true;

                                colSchema.formatter = "defaultFormat";
                                //colSchema.edittype = "checkbox";
                                
                            }

                            if (colType === "actionValidator" && actionType === "deleteItem") {
                                colSchema.isDeleteActionValidator = true;
                            }

                            if (colType === "actionValidator" && actionType === "updateItem") {
                                colSchema.isUpdateActionValidator = true;
                            }

                            //get the column locked attribute
                            colSchema.isLocked = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnLocked, false);
                            if (colSchema.isLocked) {
                                colSchema.editable = false;
                                jqGrid.hasLockedColumns = true;
                            }

                            //setup CSS classes
                            var cssClasses = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnCSS, "ui-ellipsis");
                            // always add ui-ellipsis css class
                            if (cssClasses.doesNotContain("ui-ellipsis")) {
                                cssClasses += " ui-ellipsis";
                            }
                            if (colSchema.editable === false) {
                                cssClasses += " vpgrid-not-editable";
                            }
                            if (colSchema.editable === true) {
                                cssClasses += " vpgrid-editable";
                            }

                            if (colSchema.isLocked) {
                                cssClasses += " vpgrid-locked";
                            }
                            colSchema.classes = cssClasses;

                            //bind internal vpGrid cell editing validator
                            colSchema.hasRemoteValidator = false;
                            colSchema.editrules = colSchema.editrules || {};
                            colSchema.editrules.remoteValidationUrl = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnRemoteValidationUrl, "");
                            if (isNotNullOrUndefinedOrEmpty(colSchema.editrules.remoteValidationUrl)) {
                                colSchema.hasRemoteValidator = true;
                            }


                            colSchema.editrules.custom = true;
                            colSchema.editrules.custom_func = function (value, colTitle, iCol, dataRow) {
                                try {
                                    var validationResult = jqGrid.options.afterValidateCell(value, colTitle, iCol, dataRow);
                                    return validationResult;
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            }

                            //get the column required attribute
                            colSchema.editrules.required = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnRequired, false);
                            colSchema.isRequired = colSchema.editrules.required;


                            //bind cellattr method 
                            colSchema.cellattr = function (rowid, cellValue, p1, p2, p3) {
                                try {
                                    //TODO : to be tested and finished
                                    var htmlAttributes = jqGrid.options.beforeRenderingCell(rowid, cellValue, p1, p2, p3);
                                    return htmlAttributes;

                                } catch (e) {
                                    vpGrid.logException(e);
                                    return "";
                                }

                            }


                            //get the column info
                            colSchema.hasInfo = false;
                            var colInfo = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnInfo, "");
                            //TODO : check this property does not conflict with next jqGrid version
                            colSchema.info = colInfo;
                            if (colInfo.isNotNullOrEmptyOrWhitespace()) {
                                colSchema.hasInfo = true;
                            }

                            //get the summary always update flag
                            colSchema.alwaysUpdateSummaryCell = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnSummaryAlwaysUpdate, false)


                            //build jqGrid options
                            colNames.push(colSchema.title);
                            colModel.push(colSchema);

                        } //end for (var i = 0; i < columnsCount; i++) {

                        jqGrid.options.colNames = colNames;
                        jqGrid.options.colModel = colModel;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function buildGroupHeadersOptions(element) {
                    try {
                        var selector = "th[" + vpGrid.HtmlDataTag.ColumnName + "]";
                        var jqGroupHeaders = $(element).find(selector);

                        if (jqGroupHeaders.notFound()) {
                            //TODO : log
                            return {};
                        }

                        var groupHeaders = [];

                        var headersCount = jqGroupHeaders.length;
                        for (var i = 0; i < headersCount; i++) {
                            var jqGroupHeader = $(jqGroupHeaders[i]);
                            var headerGroupSchema = {};
                            // get the colspan
                            var numberOfColumns = jqGroupHeader.toIntOrDefaultFromAttribute("colspan", 1);
                            if (numberOfColumns <= 0) {
                                vpGrid.logError({
                                    message: "colspan attribute value is : " + numberOfColumns + " on element : " + outerHtml(jqGroupHeader[0]) + " should be >= 1. This group header is not processed."
                                });
                                continue;
                            }
                            headerGroupSchema.numberOfColumns = numberOfColumns;


                            //get the column name
                            var startColumnName = jqGroupHeader.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                            if (startColumnName.isNullOrEmptyOrWhitespace()) {
                                vpGrid.logError({
                                    message: "Data attribute : " + vpGrid.HtmlDataTag.ColumnName + " on element : " + outerHtml(jqGroupHeader[0]) + " is empty or invalid. This group header is not processed."
                                });
                                continue;
                            }
                            //TODO : check if startColumnName is a real column

                            headerGroupSchema.startColumnName = startColumnName;

                            // get the title of the group header
                            headerGroupSchema.titleText = jqGroupHeader.html();

                            //build jqGrid group Headers
                            groupHeaders.push(headerGroupSchema);

                        } //end for (var i = 0; i < headersCount; i++)

                        var groupHeadersOptions = {
                            useColSpanStyle: false,
                            groupHeaders: groupHeaders
                        }

                        return groupHeadersOptions;

                    } catch (e) {
                        vpGrid.logException(e);
                        return {}
                    }
                }

                function showWelcomeMessage() {

                }

                function showLoadingMessage(rowData) {
                    try {
                        //var jqContainer = vpGrid.currentContainer();

                        //if (jqContainer.notFound()) {
                        //    //TODO : log
                        //    return;
                        //}

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridModalDialog + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        var elementsCount = jqElements.length;
                        for (var i = 0; i < elementsCount; i++) {
                            var element = jqElements[i];
                            var jqElement = $(element);

                            var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, "");
                            if (dialogId !== "vpGridLoading") {
                                continue;
                            }

                            //show modal dialog
                            jqElement.dialog("open");
                            return;

                        } // end for (var i = 0; i < elementsCount; i++)

                        //TODO : log no dialog mode found

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function hideLoadingMessage() {
                    try {
                        //var jqContainer = vpGrid.currentContainer();

                        //if (jqContainer.notFound()) {
                        //    //TODO : log
                        //    return;
                        //}

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridModalDialog + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        var elementsCount = jqElements.length;
                        for (var i = 0; i < elementsCount; i++) {
                            var element = jqElements[i];
                            var jqElement = $(element);

                            var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, "");
                            if (dialogId !== "vpGridLoading") {
                                continue;
                            }

                            //show modal dialog
                            jqElement.dialog("close");
                            return;

                        } // end for (var i = 0; i < elementsCount; i++)

                        //TODO : log no dialog mode found

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function showDeleteItemMessage(rowid) {
                    try {
                        
                        var element = vpGrid.tryFindModalDialogByName("vpGridDeleteItem");
                        var jqElement = $(element);

                        if (jqElement.notFound()) {
                            //TODO : log info
                            return;
                        }

                        // get the data row
                        var dataRow = JQGrid.rowData(rowid);

                        // set custom title if needed
                        jqElement.setCustomTitleOnThisDialog(dataRow, true);

                        //explictely show the selected row to be deleted
                        var jqRow = jqGrid.row(rowid);
                        jqRow.addClass('ui-state-to-be-deleted');

                        //show modal dialog
                        jqElement.on("dialogclose", function (event, ui) {
                            try {
                                //unselect the selected row
                                jqRow.removeClass('ui-state-to-be-deleted');


                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                        jqElement.dialog("open");

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function showCannotDeleteItemMessage(rowid) {
                    try {

                        var element = vpGrid.tryFindModalDialogByName("vpGridCannotDeleteItem");
                        var jqElement = $(element);

                        if (jqElement.notFound()) {
                            //TODO : log info
                            return;
                        }

                        // inject vpGrid property bag in the div dialog

                        //explictely show the selected row to be deleted
                        var jqRow = jqGrid.row(rowid);
                        jqRow.addClass('ui-state-to-be-deleted');

                        //show modal dialog
                        jqElement.on("dialogclose", function (event, ui) {
                            try {
                                //unselect the selected row
                                jqRow.removeClass('ui-state-to-be-deleted');


                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                        jqElement.dialog("open");

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function showErrorMessageOnLoad() {
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridPartialUI + "]";
                        selector += "[" + vpGrid.HtmlDataTag.UIIdentifier + "=vpGridErrorOnDataLoad" + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        // check if the found element is already in place
                        var isInPlace = jqElements.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIInPlace, false);
                        if (isInPlace) {
                            jqElements.showEx();
                            return;
                        }

                        var jqGridContentArea = jqGrid.contentArea();

                        if (jqGridContentArea.notFound()) {
                            vpGrid.logError({
                                functionName: "showErrorMessageOnLoad",
                                message: "jqGrid content area not found."
                            });
                        }

                        jqElements.appendTo(jqGridContentArea);
                        jqElements.attr(vpGrid.HtmlDataTag.UIInPlace, 'true');
                        jqElements.showEx();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }
                function hideErrorMessageOnLoad() {
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridPartialUI + "]";
                        selector += "[" + vpGrid.HtmlDataTag.UIIdentifier + "=vpGridErrorOnDataLoad" + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        jqElements.hideEx();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                

                function showEmptyMessageOnLoad(response) {
                    /// <signature>
                    /// <summary>Show in the UI the div that has the following signature:
                    ///     <div role="vpgrid-partial-ui"
                    ///            data-vpgrid-ui-id ="vpGridEmptyOnDataLoad" 
                    ///            style="padding-top:20px;padding-left:20px;" class="vpgrid-hidden">
                    ///           <p data-vpgrid-ui-id="customMessage.emptyOnDataLoad">
                    ///               The grid is empty because there is no item to load from your request.
                    ///           </p>
                    ///       </div>
                    /// </summary>
                    /// <param name="response" type="Object">Response object received from the Ajax call for a Read operation</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var divSelector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridPartialUI + "]";
                        divSelector += "[" + vpGrid.HtmlDataTag.UIIdentifier + "=vpGridEmptyOnDataLoad" + "]";
                        var jqDiv = $(divSelector);

                        if (jqDiv.notFound()) {
                            //TODO : log info
                            return;
                        }

                        
                        //first backup original content of the custom message
                        var customMessageSelector = '[data-vpgrid-ui-id=customMessage]';
                        var jqCustomMessage = jqDiv.find('[data-vpgrid-ui-id=customMessage]');
                        
                        var originalContent = jqCustomMessage.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.OriginalValue, undefined);
                        if (jqCustomMessage.found() && originalContent === undefined) {
                            // first time this method is called
                            // so we must register the original value
                            originalContent = jqCustomMessage.html();
                            jqCustomMessage.attr(vpGrid.HtmlDataTag.OriginalValue, originalContent);
                        }

                        //restore original content in case the server response contains no custom message
                        jqCustomMessage.html(originalContent);

                        //check if a custom message has been setup by the server
                        if (isNotNullOrUndefinedOrEmpty(response) && isNotNullOrUndefinedOrEmpty(response.customMessage)) {
                            jqCustomMessage.html(response.customMessage);
                        }

                        // check if the found element is already in place
                        var isInPlace = jqDiv.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIInPlace, false);
                        if (isInPlace) {
                            jqDiv.showEx();
                            return;
                        }

                        var jqGridContentArea = jqGrid.contentArea();

                        if (jqGridContentArea.notFound()) {
                            vpGrid.logError({
                                functionName: "showEmptyMessageOnLoad",
                                message: "jqGrid content area not found."
                            });
                        }

                        jqDiv.appendTo(jqGridContentArea);
                        jqDiv.attr(vpGrid.HtmlDataTag.UIInPlace, 'true');
                        jqDiv.showEx();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }
                function hideEmptyMessageOnLoad() {
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridPartialUI + "]";
                        selector += "[" + vpGrid.HtmlDataTag.UIIdentifier + "=vpGridEmptyOnDataLoad" + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        jqElements.hideEx();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function showOrHideEmptyMessageOnLoad(response) {
                    try {
                        if (jqGrid.isEmpty()) {
                            showEmptyMessageOnLoad(response)
                            return;
                        }

                        hideEmptyMessageOnLoad();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function showEmptyMessageOnGridComplete() {
                    try {

                        if (jqGrid.userIsNotFilteringTheGrid()) {
                            return;
                        }

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridPartialUI + "]";
                        selector += "[" + vpGrid.HtmlDataTag.UIIdentifier + "=vpGridEmptyOnGridComplete" + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        // check if the found element is already in place
                        var isInPlace = jqElements.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIInPlace, false);
                        if (isInPlace) {
                            jqElements.showEx();
                            return;
                        }

                        var jqGridContentArea = jqGrid.contentArea();

                        if (jqGridContentArea.notFound()) {
                            vpGrid.logError({
                                functionName: "showEmptyMessageOnGridComplete",
                                message: "jqGrid content area not found."
                            });
                        }

                        jqElements.appendTo(jqGridContentArea);
                        jqElements.attr(vpGrid.HtmlDataTag.UIInPlace, 'true');
                        jqElements.showEx();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }
                function hideEmptyMessageOnGridComplete() {
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridPartialUI + "]";
                        selector += "[" + vpGrid.HtmlDataTag.UIIdentifier + "=vpGridEmptyOnGridComplete" + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        jqElements.hideEx();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function showOrHideEmptyMessageOnGridComplete() {
                    try {
                        if (jqGrid.isEmpty()) {
                            showEmptyMessageOnGridComplete()
                            return;
                        }

                        hideEmptyMessageOnGridComplete();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }


                function hideDataLoadingStatus() {
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var selector = "[" + vpGrid.HtmlDataTag.UIIdentifier + "=dataLoadingStatus" + "]";
                        var jqElement = jqContainer.find(selector);

                        if (jqElement.notFound()) {
                            //TODO : log info
                            return;
                        }

                        jqElement.addClass('vpgrid-hidden');

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }
                function showDataLoadingStatus() {
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var selector = "[" + vpGrid.HtmlDataTag.UIIdentifier + "=dataLoadingStatus" + "]";
                        var jqElement = jqContainer.find(selector);

                        if (jqElement.notFound()) {
                            //TODO : log info
                            return;
                        }

                        jqElement.removeClass('vpgrid-hidden');

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function hideItemsCountStatus() {
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var selector = "[" + vpGrid.HtmlDataTag.UIIdentifier + "=itemsCountStatus" + "]";
                        var jqElement = jqContainer.find(selector);

                        if (jqElement.notFound()) {
                            //TODO : log info
                            return;
                        }

                        jqElement.addClass('vpgrid-hidden');

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }
                function showItemsCountStatus() {
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var selector = "[" + vpGrid.HtmlDataTag.UIIdentifier + "=itemsCountStatus" + "]";
                        var jqElement = jqContainer.find(selector);

                        if (jqElement.notFound()) {
                            //TODO : log info
                            return;
                        }

                        jqElement.removeClass('vpgrid-hidden');

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }


                jqGrid.placeSummaryRowsOnTop = function () {
                    /// <signature>
                    /// <summary>Move the summary row at the top under the jqGrid headers (the summary row is placed by default at the bottom of jqGrid)</summary>
                    /// </signature>
                    try {

                        if (jqGrid.options.toprow === false) {
                            // there is no summary row
                            return;
                        }


                        var jqBody = jqGrid.body();
                        var jqSummaryRowsContainer = jqGrid.summaryRowsContainer();

                        if (jqSummaryRowsContainer.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.placeSummaryRowsOnTop",
                                message: "Summary Rows Container not found : cannot be placed on top. Summary row(s) cannot be placed on top."
                            });
                            return;
                        }

                        jqSummaryRowsContainer = jqSummaryRowsContainer.detach();
                        jqSummaryRowsContainer.insertBefore(jqBody);

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.createAdditionalSummaryRows = function () {
                    /// <signature>
                    /// <summary>Add additional footer rows if needed</summary>
                    /// </signature>
                    try {

                        if (jqGrid.options.numberOfSummaryRows === 1) {
                            // there is no additional summary row
                            // do not modify default jqGrid behavior
                            return;
                        }

                        var jqSummaryRowsContainer = jqGrid.summaryRowsContainer();

                        if (jqSummaryRowsContainer.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.createAdditionalSummaryRows",
                                message: "Summary Rows container not found. Additional summary row(s) cannot be added."
                            });
                            return;
                        }

                        var defaultSummaryRowSelector = "tr[role=row].footrow";
                        var jqDefaultSummaryRow = jqSummaryRowsContainer.find(defaultSummaryRowSelector);
                        if (jqDefaultSummaryRow.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.createAdditionalSummaryRows",
                                message: "Cannot find default summary row : '" + jqDefaultSummaryRow.selector + "'"
                            });
                            return;
                        }

                        //add additional summary rows
                        var rowsCount = jqGrid.options.numberOfSummaryRows;
                        var jqTableBody = jqDefaultSummaryRow.parent();
                        for (var i = 1; i < rowsCount; i++) {
                            var jqClonedSummaryRow = jqDefaultSummaryRow.clone()
                            var j = i + 1;
                            var summaryRowId = "SummaryRow" + j ;
                            var summaryRowClassName = "summary-row-" + j ;
                            jqClonedSummaryRow.attr(vpGrid.HtmlDataTag.UIIdentifier, summaryRowId);
                            jqClonedSummaryRow.addClass(summaryRowClassName);

                            jqClonedSummaryRow.appendTo(jqTableBody);
                        }

                        //tag default summary row with vp grid id
                        jqDefaultSummaryRow.attr(vpGrid.HtmlDataTag.UIIdentifier, "SummaryRow1");
                        jqDefaultSummaryRow.addClass("summary-row-1");

                        jqSummaryRowsContainer.height(jqSummaryRowsContainer.height() * rowsCount);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }


                jqGrid.tagCellsInDefaultSummaryRow = function () {
                    /// <signature>
                    /// <summary>Add additional vpgrid data tag to the default summary row cells</summary>
                    /// </signature>
                    try {

                        if (jqGrid.options.numberOfSummaryRows === 0) {
                            // there is no  summary row
                            // do not modify default jqGrid behavior
                            return;
                        }

                        var jqSummaryRowsContainer = jqGrid.summaryRowsContainer();

                        if (jqSummaryRowsContainer.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.dataTagDefaultSummaryRow",
                                message: "Summary Rows container not found. Default summary row cannot be tagged with vpgrid data tag."
                            });
                            return;
                        }

                        var defaultSummaryRowSelector = "tr[role=row].footrow";
                        var jqDefaultSummaryRow = jqSummaryRowsContainer.find(defaultSummaryRowSelector);
                        if (jqDefaultSummaryRow.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.dataTagDefaultSummaryRow",
                                message: "Cannot find default summary row : '" + jqDefaultSummaryRow.selector + "'"
                            });
                            return;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : cannot apply data tags on cells of the summary row"
                            });
                            return;
                        }


                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var cellName = colModel.name;
                            
                            var cellSelector = jqGrid.defaultJqGridCellSelectorForCol(cellName);
                            jqDefaultSummaryRow.find(cellSelector).attr(vpGrid.HtmlDataTag.ColumnName, cellName);
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                // row checkbox managment
                jqGrid.lastSelectedCheckboxId = "";
                jqGrid.currentSelectedCheckboxId = "";

                function uncheckRow(checkboxId) {
                    try {
                        if (isNotString(checkboxId)) {
                            vpGrid.logError({
                                functionName: "uncheckRow",
                                message: "checkboxId is not a string"
                            });
                            return;
                        }

                        if (checkboxId.isNullOrEmptyOrWhitespace()) {
                            return;
                        }

                        var checkboxSelector = "input[type=checkbox][id=" + checkboxId + "]";
                        var jqCheckbox = $(checkboxSelector);

                        if (jqCheckbox.notFound()) {
                            vpGrid.logError({
                                functionName: "uncheckRow",
                                message: "Cannot find checkbox : '" + jqCheckbox.selector + "'"
                            });
                            return;
                        }

                        jqCheckbox[0].checked = false;
                        jqCheckbox.removeAttr('checked');
                        jqCheckbox.closest("tr[role=row]").removeClass('ui-state-highlight');

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function checkRow(checkboxId) {
                    try {
                        if (isNotString(checkboxId)) {
                            vpGrid.logError({
                                functionName: "checkRow",
                                message: "checkboxId is not a string"
                            });
                            return;
                        }

                        if (checkboxId.isNullOrEmptyOrWhitespace()) {
                            return;
                        }

                        var checkboxSelector = "input[type=checkbox][id=" + checkboxId + "]";
                        var jqCheckbox = $(checkboxSelector);

                        if (jqCheckbox.notFound()) {
                            vpGrid.logError({
                                functionName: "checkRow",
                                message: "Cannot find checkbox : '" + jqCheckbox.selector + "'"
                            });
                            return;
                        }

                        jqCheckbox[0].checked = true;
                        //jqCheckbox.removeAttr('checked');
                        //jqCheckbox.closest("tr[role=row]").removeClass('ui-state-highlight');

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function ensureOnlyOneRowCanBeChecked() {
                    try {
                        if (vpGrid.options.enableMultiSelect) {
                            // multi select is authorized
                            return;
                        }

                        //bind click event handler on every checkbox item
                        var jqRowCheckboxes = jqGrid.rowCheckboxes();

                        if (jqRowCheckboxes.notFound()) {
                            //TODO : log
                            return;
                        }

                        //bind change event in an asynchronous loop
                        var checkboxArray = $.makeArray(jqRowCheckboxes);
                        vpGrid.executeAsyncLoopOnArray(checkboxArray,
                            function (i, item) {
                                if (item.hasAttribute(vpGrid.HtmlDataTag.HandlersRegistered)) {
                                    return; //continue
                                }
                                $(item).removeAttr('disabled');
                                $(item).bind('change', function (e) {
                                    try {
                                        if (this.checked === false) {

                                            return;
                                        }

                                        if (isNullOrUndefinedOrEmpty(this.id)) {

                                            return;
                                        }

                                        if (jqGrid.lastSelectedCheckboxId === this.id) {

                                            return;
                                        }

                                        var id1 = this.id;
                                        var id2 = jqGrid.lastSelectedCheckboxId;
                                        executeAsync(this, function () {
                                            try {
                                                uncheckRow(id2);
                                                checkRow(id1);
                                                jqGrid.currentSelectedCheckboxId = id1;
                                                jqGrid.lastSelectedCheckboxId = id1;

                                            } catch (ex) {
                                                vpGrid.logException(ex);
                                            }
                                            finally {
                                                executeAsync(this, function () {
                                                    activateDeactivateRibbonContent();
                                                }, 100);
                                            }
                                        }, 100);


                                    } catch (ex) {
                                        vpGrid.logException(ex);
                                    }
                                    finally {
                                        e.stopPropagation();
                                        executeAsync(this, function () {
                                            activateDeactivateRibbonContent();
                                        }, 100);
                                    }
                                });//end change event handler)
                                $(item).attr(vpGrid.HtmlDataTag.HandlersRegistered, "true");
                            },
                            jqGrid)

                        // do not remove these commented lines
                        // -> for the sake of comparison synchronous vs asynchronous event binding
                        //jqRowCheckboxes.bind('change', function (e) {
                        //    try {
                        //        if (this.checked === false) {

                        //            return;
                        //        }

                        //        if (isNullOrUndefinedOrEmpty(this.id)) {

                        //            return;
                        //        }

                        //        if (jqGrid.lastSelectedCheckboxId === this.id) {

                        //            return;
                        //        }

                        //        var id1 = this.id;
                        //        var id2 = jqGrid.lastSelectedCheckboxId;
                        //        executeAsync(this, function () {
                        //            try {
                        //                uncheckRow(id2);
                        //                checkRow(id1);
                        //                jqGrid.currentSelectedCheckboxId = id1;
                        //                jqGrid.lastSelectedCheckboxId = id1;

                        //            } catch (ex) {
                        //                vpGrid.logException(ex);
                        //            }
                        //            finally {
                        //                executeAsync(this, function () {
                        //                    activateDeactivateRibbonContent();
                        //                }, 100);
                        //            }
                        //        }, 100);


                        //    } catch (ex) {
                        //        vpGrid.logException(ex);
                        //    }
                        //    finally {
                        //        e.stopPropagation();
                        //        executeAsync(this, function () {
                        //            activateDeactivateRibbonContent();
                        //        }, 100);
                        //    }
                        //});


                        

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }


                function activateDeactivateRibbonContent() {
                    try {
                        
                        //bind click event handler on every checkbox item
                        var jqRowCheckboxes = jqGrid.rowCheckboxes();

                        if (jqRowCheckboxes.notFound()) {
                            //TODO : log
                            return;
                        }

                        var itemCount = jqRowCheckboxes.length;
                        var selectedItemCount = 0;
                        for (var i = 0; i < itemCount; i++) {
                            var checkbox = jqRowCheckboxes[i];
                            if (checkbox.checked) {
                                selectedItemCount += 1;
                            }
                        }

                        //get all buttons that have the data attribute data-vpgrid-ui-disabled-on
                        var jqRibbonContainer = jqGrid.ribbonContainer();
                        if (jqRibbonContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var buttonsSelector = "button[" + vpGrid.HtmlDataTag.UIDisabledOn + "]";
                        var jqButtons = jqRibbonContainer.find(buttonsSelector);
                        if (jqButtons.notFound()) {
                            //TODO : log
                            return;
                        }

                        var buttonsCount = jqButtons.length;
                        for (var i = 0; i < buttonsCount; i++) {
                            var button = jqButtons[i];
                            var jqButton = $(button);
                            var disabledOn = jqButton.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIDisabledOn, "");
                            if (disabledOn === "noItemSelected" && selectedItemCount === 0) {
                                jqButton.attr('disabled', true).addClass("ui-state-disabled");
                                continue;
                            }

                            if (disabledOn === "noItemSelected" && selectedItemCount > 0) {
                                //TODO : raise event
                                var eventArgs = {
                                    uiId: jqButton.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIIdentifier, ""),
                                    cancel: false,
                                    selectedRowData : jqGrid.selectedRowData()
                                };
                                onUIElementEnabling(button, eventArgs);

                                if (eventArgs.cancel === true) {
                                    jqButton.attr('disabled', true).addClass("ui-state-disabled");
                                    continue;
                                }

                                jqButton.removeAttr('disabled').removeClass("ui-state-disabled");

                                continue;
                            }

                            if (disabledOn === "custom") {
                                //raise event to let listeners enable/disable the button
                                var eventArgs = {
                                    uiId: jqButton.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIIdentifier,""),
                                    cancel: false
                                };
                                onUIElementDisabling(button, eventArgs);
                                if (eventArgs.cancel === true) {
                                    jqButton.removeAttr('disabled').removeClass("ui-state-disabled");
                                    continue;
                                }
                                jqButton.attr('disabled', true).addClass("ui-state-disabled");
                                continue;
                            }



                            //TODO : raise event to enable listener activate/decativate button 

                            //TODO : log disableOn value not implemented
                            vpGrid.logError({
                                functionName : "activateDeactivateRibbonContent",
                                message: "Data attribute '" + vpGrid.HtmlDataTag.UIDisabledOn + "' has a not implemented value : '" + disabledOn + "' on element : \n " + outerHtml(button)
                            });

                        }

                        

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }






                // end // row checkbox managment

                jqGrid.initActivateDeactivateRibbonContent = function() {
                    try {

                        //get all buttons that have the data attribute data-vpgrid-ui-disabled="true"
                        var jqRibbonContainer = jqGrid.ribbonContainer();
                        if (jqRibbonContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var buttonsSelector = "button[" + vpGrid.HtmlDataTag.UIDisabled + "=true]";
                        var jqButtons = jqRibbonContainer.find(buttonsSelector);
                        if (jqButtons.notFound()) {
                            //TODO : log
                            return;
                        }

                        var buttonsCount = jqButtons.length;
                        for (var i = 0; i < buttonsCount; i++) {
                            var button = jqButtons[i];
                            var jqButton = $(button);

                            var eventArgs = {
                                uiId: jqButton.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIIdentifier, ""),
                                cancel: false
                            };
                            onUIElementDisabling(button, eventArgs);
                            if (eventArgs.cancel === true) {
                                jqButton.removeAttr('disabled').removeClass("ui-state-disabled");
                                continue;
                            }
                            jqButton.attr('disabled', true).addClass("ui-state-disabled");

                        }



                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }



                jqGrid.bindAutocompleteOnSearchInputs = function () {
                    /// <signature>
                    /// <summary>bind autocomplete widget on search input boxes within the search toolbar</summary>
                    /// </signature>
                    try {
                        // check if search tool bar functionnality  is enabled
                        if (vpGrid.options.enableFilterToolbar === false) {
                            return;
                        }

                        var jqElements = jqGrid.searchToolbarInputs();
                        var count = jqElements.length;
                        for (var i = 0; i < count; i++) {
                            var element = jqElements[i];
                            var jqElement = $(element);
                            var colname = jqElement.toStringOrDefaultFromAttribute("name", "");
                            if (colname.isNullOrEmptyOrWhitespace()) {
                                continue;
                            }
                            var colValues = jqGrid.colValues(colname);
                            if (isNullOrUndefinedOrEmpty(colValues)) {
                                continue;
                            }

                            bindAutoCompleteWidgetWithDataOnElement(element, colValues);

                            // bind to select event to programmatically filter the grid 
                            jqElement.on("autocompleteselect", function (event, ui) {
                                try {
                                    executeAsync(this,jqGrid.filterGridFromSearchToolbar);

                                } catch (e) {
                                    vpGrid.logException(e);
                                }

                            });


                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.currentColModels = function () {
                    try {
                        // get the jqGrid host table
                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot get colModels jqGrid object because jqGrid host is not found."
                            });
                            return null;
                        }

                        var colModels = jqGridHost.jqGrid('getGridParam', 'colModel');
                        return colModels;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.colModelOf = function (colName) {
                    /// <signature>
                    /// <summary>Get the colmodel the named column.</summary>
                    /// <param name="colName" type="String">Name of the column from which to get the colModel.</param>
                    /// <returns type="Object">Returns the colModel object of the column. Returns null if colModel is not found.</returns>
                    /// </signature>
                    try {
                        if (isNotString(colName)) {
                            //TODO : log
                            return null;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : jqGrid.colModelOf is stopped. colName='" + colName + "'"
                            });
                            return;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var cellName = colModel.name;
                            if (colModel.name === colName) {
                                return colModel;
                            }
                        }
                        

                        return null;


                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }

                }

                jqGrid.colIndexOf = function (colName) {
                    /// <signature>
                    /// <summary>Get the column index (iCol) for the named column.</summary>
                    /// <param name="colName" type="String">Name of the column from which to get the index of the column</param>
                    /// <returns type="Number">Returns the index of the column. Returns -1 if column is not found.</returns>
                    /// </signature>
                    try {
                        if (isNotString(colName)) {
                            //TODO : log
                            return -1;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : jqGrid.colIndexOf is stopped. colName='" + colName + "'"
                            });
                            return;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var cellName = colModel.name;
                            if (colModel.name === colName) {
                                return i;
                            }
                        }


                        return -1;


                    } catch (e) {
                        vpGrid.logException(e);
                        return -1;
                    }

                }


                jqGrid.colNameAtCellIndex = function (index) {
                    /// <signature>
                    /// <summary>Get the column name for the specified index of the TD within a TR row</summary>
                    /// <param name="index" type="Number">Index of the table cell (<td>) within a jqgrid row</param>
                    /// <returns type="String">Returns the name of the column. Returns null if column is not found.</returns>
                    /// </signature>
                    try {
                        if (isNotNumber(index)) {
                            //TODO : log
                            return null;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : jqGrid.colIndexOf is stopped. colName='" + colName + "'"
                            });
                            return;
                        }

                        var colCount = colModels.length;
                        var visibleColCounter = -1;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            if (i === index) {

                                return colModel.name;
                            }
                           
                        }

                        return null;


                    } catch (e) {
                        vpGrid.logException(e);
                        return;
                    }

                }


                jqGrid.firstVisibleColumnName = function () {
                    /// <signature>
                    /// <summary>Get the column name of the first visible column in the grid</summary>
                    /// <returns type="String">Returns the name of the column. Returns null if column is not found.</returns>
                    /// </signature>
                    try {
                        
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: "jqGrid.firstVisibleColumnName",
                                message: "ColModels not found."
                            });
                            return;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            if (colModel.hidden === false) {
                                var columnName = colModel.name;
                                return columnName;
                            }
                        }

                        return null;


                    } catch (e) {
                        vpGrid.logException(e);
                        return;
                    }

                }



                jqGrid.rowData = function (rowId) {
                    try {
                        // get the jqGrid host table
                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot get rowData object because jqGrid host is not found."
                            });
                            return null;
                        }

                        if (isNullOrUndefinedOrEmpty(rowId)) {
                            vpGrid.logError({
                                message: "input parameter is not valid. rowId value is : '" + rowId + "'"
                            });
                            return null;
                        }

                        var data = jqGridHost.jqGrid('getRowData', rowId);
                        return data;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }



                jqGrid.summaryRowData = function (rowId) {
                    try {
                        // get the jqGrid host table
                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot get rowData object because jqGrid host is not found."
                            });
                            return null;
                        }

                        if (isNullOrUndefinedOrEmpty(rowId)) {
                            vpGrid.logError({
                                message: "input parameter is not valid. rowId value is : '" + rowId + "'"
                            });
                            return null;
                        }

                        var data = jqGridHost.jqGrid('getSummaryRowData', rowId);
                        return data;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }




                jqGrid.selectedRowData = function () {
                    /// <signature>
                    /// <summary>Get the row data from the first selected Item.
                    ///         A selected item is a row for which the first column checkbox has been checked
                    ///</summary>
                    /// <returns type="Object">Returns a literal object that is the jqGrid datarow object.</returns>
                    /// </signature>
                    try {
                        // get the jqGrid host table
                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot get rowData object because jqGrid host is not found."
                            });
                            return null;
                        }

                        var jqSelectedRow = jqGrid.selectedRow();

                        if (jqSelectedRow.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.selectedRowData",
                                message: "Current selected row cannot be found."
                            });
                            return null;
                        }

                        var rowId = jqSelectedRow[0].id;
                        if (isNullOrUndefinedOrEmpty(rowId)) {
                            vpGrid.logError({
                                functionName: "jqGrid.selectedRowData",
                                message: "input parameter is not valid. rowId value is : '" + rowId + "'"
                            });
                            return null;
                        }

                        var data = jqGridHost.jqGrid('getRowData', rowId);
                        return data;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.emptyRowData = function () {
                    /// <signature>
                    /// <summary>Build a new data row literal object. 
                    ///         Each property is set with the default value defined in the colModel
                    ///</summary>
                    /// <returns type="Object">Litteral object where each property is an existing column. Returns null if something goes wrong.</returns>
                    /// </signature>
                    try {
                        var rowData = {};

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : cannot build an empty data row object"
                            });
                            return null;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var cellName = colModel.name;
                            var cellValue = '';
                            
                            if (colModel.isKey === true) {
                                cellValue = 'clientId' + vpGrid.guid++;
                                rowData[cellName] = cellValue;
                                continue;
                            }

                            //set the isDeletable column
                            if (colModel.isDeleteActionValidator === true) {
                                cellValue = true;
                                rowData[cellName] = cellValue;
                                continue;
                            }

                            //set the isUpdatable column
                            if (colModel.isUpdateActionValidator === true) {
                                cellValue = true;
                                rowData[cellName] = cellValue;
                                continue;
                            }

                            // TODO : feed emptyRowData with default values set from colmodel

                            rowData[cellName] = cellValue;

                        }

                        return rowData;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.rows = function () {
                    /// <signature>
                    /// <summary>Try to find all rows displayed in jqGrid</summary>
                    /// <returns type="Object">Returns the jqGrid table rows found by jQuery</returns>
                    /// </signature>
                    try {

                        var jqGridHost = jqGrid.host();
                        // first step : find all rows in jqGrid                        
                        var rowsSelector = "tr[role=row]";
                        var jqRows = jqGridHost.find(rowsSelector);

                        if (jqRows.notFound()) {
                            vpGrid.logError({
                                message: "Cannot find jqGrid rows because the following selector is not found : '" + jqRows.selector + "'",
                                functionName: "jqGrid.rows"
                            });
                        }

                        //update the total filtered item count
                        jqGrid.filteredItemCount = jqRows.length - 1;

                        return jqRows;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.isEmpty = function () {
                    /// <signature>
                    /// <summary>Check if the grid is empty</summary>
                    /// <returns type="Object">Returns true if the grid shows no data</returns>
                    /// </signature>
                    try {

                        var jqGridHost = jqGrid.host();
                        // first step : find all rows in jqGrid                        
                        var rowsSelector = "tr[role=row]";
                        var jqRows = jqGridHost.find(rowsSelector);

                        if (jqRows.notFound()) {
                            vpGrid.logError({
                                message: "Cannot find jqGrid rows because the following selector is not found : '" + jqRows.selector + "'",
                                functionName: "jqGrid.isEmpty"
                            });
                        }

                        if (jqRows.length === 1) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.firstRow = function () {
                    /// <signature>
                    /// <summary>Get the first row showed in the grid</summary>
                    /// <returns type="Object">Returns the found row as a DOM element. Returns null if the grid is empty.</returns>
                    /// </signature>
                    try {

                        var jqGridHost = jqGrid.host();
                        // first step : find all rows in jqGrid                        
                        var rowsSelector = "tr[role=row]";
                        var jqRows = jqGridHost.find(rowsSelector);

                        if (jqRows.notFound()) {
                            return null;
                        }

                        if (jqRows.length === 1) {
                            return null;
                        }

                        return jqRows[1];

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.unselectAllLines = function () {
                    try {
                        var jqRowCheckboxes = jqGrid.rowCheckboxes();

                        if (jqRowCheckboxes.found()) {
                            jqRowCheckboxes.removeAttr('checked');
                        }

                        //unhighlight all lines
                        var jqRows = jqGrid.rows();
                        jqRows.removeClass('ui-state-highlight');

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.rowCheckboxes = function () {
                    /// <signature>
                    /// <summary>Try to find, in jqFrid, all row checkboxes, excluding the one that is in the header</summary>
                    /// <returns type="Object">Returns the jqGrid checkboxes (used for item selection) found by jQuery</returns>
                    /// </signature>
                    try {

                        if (jqGrid.options.multiselect === false) {
                            // there is no checbox configured for row selection
                            return $(null);
                        }

                        var jqRows = jqGrid.rows();
                        // second step : find the cell in edit mode
                        var cellname = "cb";
                        var cellSelector = jqGrid.defaultJqGridCellSelectorForCol( cellname);
                        var jqCells = jqRows.find(cellSelector);
                        if (jqCells.notFound()) {
                            // TODO : log something if multiselect: true
                            return $(null);
                        }

                        //bind data tag if not already done
                        //jqCells.attr(vpGrid.HtmlDataTag.ColumnName, "cb"); --> now done in the patch addRowData

                        //third step : find the input checkbox elements 
                        var jqCheckboxes = jqCells.find("input[type=checkbox]");

                        if (jqCheckboxes.notFound()) {
                            //TODO : log
                        }

                        return jqCheckboxes;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.hideHeaderCheckbox = function () {
                    /// <signature>
                    /// <summary>hide, in jqGrid, the checkbox that is in the header (first column on the left)</summary>
                    /// </signature>
                    try {

                        if (jqGrid.options.multiselect === false) {
                            // there is no checbox configured for row selection
                            return;
                        }

                        var jqGridContainer = jqGrid.container();
                        // first step : find row in jqGrid that hosts the header checkbox                        
                        var rowSelector = "tr[role=rowheader]";
                        var jqRow = jqGridContainer.find(rowSelector);
                        // second step : find the cell in edit mode
                        var cellname = "cb";
                        var cellSelector = "th[id=" + jqGrid.Id + "_" + cellname + "]";
                        var jqCell = jqRow.find(cellSelector);
                        if (jqCell.notFound()) {
                            vpGrid.logError({
                                message: "Cannot find selector : '" + jqCell.selector + "'",
                                functionName: "hideHeaderCheckbox"
                            });
                            return;
                        }

                        //third step : find the input checkbox elements 
                        var jqCheckbox = jqCell.find("input[type=checkbox]");

                        jqCheckbox.addClass('vpgrid-hidden');

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                function onRowChecked() {

                }

                jqGrid.filterGridFromSearchToolbar = function () {
                    try {
                        // check if search tool bar functionnality  is enabled
                        if (vpGrid.options.enableFilterToolbar === false) {
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot filter jqGrid rows because the following selector is not found : '" + jqGridHost.selector + "'",
                                functionName: "jqGrid.filterGridFromSearchToolbar"
                            });
                            return;
                        }

                        jqGridHost[0].triggerToolbar();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.searchToolbarInputs = function () {
                    /// <signature>
                    /// <summary>Get all search input boxes within the search toolbar</summary>
                    /// </signature>
                    try {
                        var jqGridContainer = jqGrid.container();
                        if (jqGridContainer.notFound()) {
                            //TODO : log
                            return $(null);
                        }

                        // first step : find row in jqGrid that hosts the search toolbar                        
                        var rowSelector = "tr[role=rowheader].ui-search-toolbar";
                        var jqRow = jqGridContainer.find(rowSelector);

                        //second step : find search input boxes
                        var inputSelector = "input[type=text][id^=gs_]";
                        var jqInput = jqRow.find(inputSelector);
                        if (jqInput.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.searchToolbarInputs",
                                message: "Cannot configure input search toolbar because the following selector was not found : '" + jqInput.selector + "'",
                                info: "Check the version of the jqGrid library."
                            });
                            return $(null);
                        }

                        return jqInput;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }

                }

                jqGrid.searchInputForCol = function (colName) {
                    /// <signature>
                    /// <summary>Get the input search box within the search toolbar for the specified column named colName.</summary>
                    /// <param name="colName" type="String">Name of the column in the grid.</param>
                    /// <returns type="Object">jQuery object of the found input search field.</returns>
                    /// </signature>
                    try {
                        var jqGridContainer = jqGrid.container();
                        if (jqGridContainer.notFound()) {
                            //TODO : log
                            return $(null);
                        }

                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.searchInputForCol",
                                message: "Input column name '" + colName + "'," + " does not exist."
                            });
                            return $(null);
                        }

                        // first step : find row in jqGrid that hosts the search toolbar                        
                        var rowSelector = "tr[role=rowheader].ui-search-toolbar";
                        var jqRow = jqGridContainer.find(rowSelector);

                        if (jqRow.notFound()) {
                            //TODO : log
                            return $(null);
                        }

                        //second step : find search input box
                        var inputSelector = jqGrid.searchInputSelectorForCol(colName);
                        var jqInput = jqRow.find(inputSelector);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return $(null);
                        }

                        return jqInput;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }

                }

                jqGrid.updateSearchInputDataSourceForCol = function (colName,cellValue) {
                    /// <signature>
                    /// <summary>Get the input search box within the search toolbar for the specified column named colName.
                    ///          Then update the autocomplete data source that is linked with this input field.
                    ///          This method should be called each time a new or modified value is entered in a grid cell.
                    ///</summary>
                    /// <param name="colName" type="String">Name of the column in the grid.</param>
                    /// <param name="cellValue" type="String">Value to be added to the autocomplete data source of the search input field</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (vpGrid.options.enableFilterToolbar === false) {
                            return;
                        }

                        var jqGridContainer = jqGrid.container();
                        if (jqGridContainer.notFound()) {
                            //TODO : log
                            return ;
                        }

                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateSearchInputDataSourceForCol",
                                message: "Input column name '" + colName + "'," + " does not exist."
                            });
                            return ;
                        }

                        if (isNullOrUndefinedOrEmpty(cellValue)) {
                            return;
                        }

                        //check if the column is filterable
                        var colModel = jqGrid.colModelOf(colName);
                        if (colModel.search === false) {
                            return;
                        }

                        var jqInput = jqGrid.searchInputForCol(colName);
                        if (jqInput.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateSearchInputDataSourceForCol",
                                message: "Input search field not found for column '" + colName + "'. Cannot update the autocomplete data source."
                            });
                            return;
                        }

                        if (jqInput.autocomplete === undefined) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateSearchInputDataSourceForCol",
                                message: "Input search field for column '" + colName + "'  has no autocomplete bound to it."
                            });
                            return;
                        }


                        try {
                            var datasourceArray = jqInput.autocomplete("option", "source");
                            datasourceArray.insertOnce(cellValue);
                        } catch (e) {
                            // autocomplete was bound with an empty data source array
                            var dataSourceArray = [];
                            dataSourceArray.push(cellValue);
                            bindAutoCompleteWidgetWithDataOnElement(jqInput[0], dataSourceArray);
                        }
                        
                        
                        

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }


                jqGrid.updateSearchInputDataSourceForColWithValues = function (colName, cellValues) {
                    /// <signature>
                    /// <summary>Get the input search box within the search toolbar for the specified column named colName.
                    ///          Then update the autocomplete data source that is linked with this input field.
                    ///          This method should be called each time a new or modified value is entered in a grid cell.
                    ///</summary>
                    /// <param name="colName" type="String">Name of the column in the grid.</param>
                    /// <param name="cellValues" type="Array">Array of string : data source array to link to the autocomplete data source of the search input field</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (vpGrid.options.enableFilterToolbar === false) {
                            return;
                        }

                        var jqGridContainer = jqGrid.container();
                        if (jqGridContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateSearchInputDataSourceForColWithValues",
                                message: "Input column name '" + colName + "'," + " does not exist."
                            });
                            return;
                        }

                        if (isNotArray(cellValues)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateSearchInputDataSourceForColWithValues",
                                message: "input cellValues isnot an array but is : '" + cellValues + "'."
                            });
                            return;
                        }

                        //check if the column is filterable
                        var colModel = jqGrid.colModelOf(colName);
                        if (colModel.search === false) {
                            return;
                        }

                        var jqInput = jqGrid.searchInputForCol(colName);
                        if (jqInput.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateSearchInputDataSourceForColWithValues",
                                message: "Input search field not found for column '" + colName + "'. Cannot update the autocomplete data source."
                            });
                            return;
                        }

                        if (jqInput.autocomplete === undefined) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateSearchInputDataSourceForColWithValues",
                                message: "Input search field for column '" + colName + "'  has no autocomplete bound to it."
                            });
                            return;
                        }

                        try {
                            var datasourceArray = jqInput.autocomplete("option", "source");
                            datasourceArray.clear();
                            datasourceArray.addArray(cellValues);
                        } catch (e) {
                            // autocomplete was bound with an empty data source array
                            bindAutoCompleteWidgetWithDataOnElement(jqInput[0], cellValues);
                        }




                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                jqGrid.updateSearchInputDataSourcesWithDataRow = function (dataRow) {
                    /// <signature>
                    /// <summary>Update the autocomplete data source of the search input fields from data found in the input data row.
                    ///          This method should be called each time a new row is inserted in the grid.
                    ///</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (vpGrid.options.enableFilterToolbar === false) {
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGRid.updateSearchInputDataSourcesWithDataRow",
                                message: "input data row object is null or empty : '" + dataRow + "'"
                            });
                            return;
                        }

                        for (var p in dataRow) {
                            //check if the property is a column name
                            if (jqGrid.colDoesNotExist(p)) {
                                //TODO : log
                                continue;
                            }

                            //update the autocomplete data source
                            var newValue = dataRow[p];
                            jqGrid.updateSearchInputDataSourceForCol(p, newValue.toString());

                        } // end for (var p in responseData) {

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.userIsFilteringTheGrid = function () {
                    /// <signature>
                    /// <summary>Check if the user as entered some text in at least one of the input search fields
                    ///</summary>
                    /// <returns type="Boolean">Return true if has put some text in one of the field of the search toolbar</returns>
                    /// </signature>
                    try {
                        if (vpGrid.options.enableFilterToolbar === false) {
                            return false;
                        }

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.searchInputsAreAllEmpty",
                                message: "Cannot find vpGrid container in the DOM.",
                                info: "Check that the <div role=vpgrid-container> exists in the web page."
                            });
                            return false;
                        }

                        var searchToolbarSelector = 'tr.ui-search-toolbar';
                        var jqSearchToolbar = jqContainer.find(searchToolbarSelector);
                        if (jqSearchToolbar.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.searchInputsAreAllEmpty",
                                message: "Cannot find DOM selector : '" + searchToolbarSelector + "' inside : '" + jqContainer.selector + "'"
                                
                            });
                            return false;
                        }

                        var searchInputSelector = 'td.ui-search-input input';
                        var jqSearchInputs = jqSearchToolbar.find(searchInputSelector);
 
                        var searchInputCounter = jqSearchInputs.length;
                        for (var i = 0; i < searchInputCounter; i++) {

                            var searchInput = jqSearchInputs[i];
                            var searchValue = $(searchInput).val();
                            if (isNotNullOrUndefinedOrEmpty(searchValue)) {
                                return true;
                            }

                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.userIsNotFilteringTheGrid = function() {
                    return jqGrid.userIsFilteringTheGrid() === false;
                }

                jqGrid.userIsFilteringTheGridOnCol = function (colName) {
                    /// <signature>
                    /// <summary>Check if the user as entered some text in the search input field of input column.
                    ///</summary>
                    /// <param name="colName" type="String">Name of the column in the grid.</param>
                    /// <returns type="Boolean">Return true if user has put some text in the field of the search toolbar for column named colName.</returns>
                    /// </signature>
                    try {
                        if (vpGrid.options.enableFilterToolbar === false) {
                            return false;
                        }

                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.userIsFilteringTheGridOnCol",
                                message: "Input column name '" + colName + "'," + " does not exist."
                            });
                            return false;
                        }

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.userIsFilteringTheGridOnCol",
                                message: "Cannot find vpGrid container in the DOM.",
                                info: "Check that the <div role=vpgrid-container> exists in the web page."
                            });
                            return false;
                        }

                        var searchToolbarSelector = 'tr.ui-search-toolbar';
                        var jqSearchToolbar = jqContainer.find(searchToolbarSelector);
                        if (jqSearchToolbar.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.userIsFilteringTheGridOnCol",
                                message: "Cannot find DOM selector : '" + searchToolbarSelector + "' inside : '" + jqContainer.selector + "'"

                            });
                            return false;
                        }

                        var searchInputSelector = 'td.ui-search-input input[name=' + colName + ']';
                        var jqSearchInput = jqSearchToolbar.find(searchInputSelector).first();

                        var searchValue = jqSearchInput.val();
                        if (isNotNullOrUndefinedOrEmpty(searchValue)) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.hasRemoteFilterThatTargetsCol = function (colName) {
                    /// <signature>
                    /// <summary>Check if the in input column is targeted by a remote filter.
                    ///         A remote filter targets a column when the DOM element has the following signature:
                    ///             <select id="..."
                    ///                 role="vpgrid-remote-data-filter"
                    ///                 data-vpgrid-remote-data-filter-key="Statut"
                    ///                 data-vpgrid-remote-data-filter-column-name="statut"  -> name of the targeted column
                    ///                 data-vpgrid-ui-element="true"
                    ///                 data-vpgrid-datasource="/_layouts/.../GetKeyValues_StatutsActivite.aspx"
                    ///                 data-vpgrid-datasource-type="web"
                    ///                 data-vpgrid-timeline-sequence="GridLoading"
                    ///                 data-vpgrid-handlers='{"change" : { "handler" : "vpGrid.reloadGrid", "params":"",  "async" : true, "asyncKey" : "onStatutChange"}}'
                    ///             >
                    ///         </select>
                    ///</summary>
                    /// <param name="colName" type="String">Name of the column in the grid.</param>
                    /// <returns type="Boolean">Return true if input column name is targeted by a remote filter.</returns>
                    /// </signature>
                    try {
                        
                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.hasRemoteFilterThatTargetsCol",
                                message: "Input column name '" + colName + "'," + " does not exist."
                            });
                            return false;
                        }

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.hasRemoteFilterThatTargetsCol",
                                message: "Cannot find vpGrid container in the DOM.",
                                info: "Check that the <div role=vpgrid-container> exists in the web page."
                            });
                            return false;
                        }

                        var remoteFilterSelector = '[role=' + vpGrid.HtmlRoleAttribute.RemoteDataFilter + ']';
                        remoteFilterSelector = remoteFilterSelector + '[' + vpGrid.HtmlDataTag.RemoteDataFilterColumnName + '=' + colName + ']';
                        var jqRemoteFilter = jqContainer.find(remoteFilterSelector);
                        if (jqRemoteFilter.notFound()) {
                            
                            return false;
                        }

                        return true;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }



                jqGrid.updateSearchInputDataSourcesWithFilteredDataRows = function (dataRows) {
                    /// <signature>
                    /// <summary>Update the autocomplete data source of the search input fields from the result of the previous search operation
                    ///          This method should be called each time the grid is filtered.
                    ///</summary>
                    /// <param name="dataRows" type="Array">Array of Literal objects containing the rows found in the previous search operation.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (vpGrid.options.enableFilterToolbar === false) {
                            return;
                        }

                        if (isNotArray(dataRows)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateSearchInputDataSourcesWithFilteredDataRows",
                                message: "input dataRows is not an array."
                            });
                            return;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateSearchInputDataSourcesWithFilteredDataRows",
                                message: "ColModels not found : updating of the serach input fields autocomplete data source is stopped."
                            });
                            return;
                        }


                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var colName = colModel.name;

                            //check if the column is hidden
                            if (colModel.hidden) {
                                continue;
                            }

                            //check if the column is filterable
                            if (colModel.search === false) {
                                continue;
                            }

                            if (jqGrid.userIsFilteringTheGridOnCol(colName)) {
                                //update the autocomplete of the search input only for search fields not yet filled by the user
                                continue;
                            }

                            //get the column values
                            var colValues = jqGrid.colValuesFromDataArray(colName, dataRows);
                            // update the autocomplete bound to the input search filter.
                            jqGrid.updateSearchInputDataSourceForColWithValues(colName, colValues);

                        } // end for (var i = 0; i < colCount; i++) {


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }





                jqGrid.colValues = function (colname) {
                    /// <signature>
                    /// <summary>Get all distinct values which are not null or empty from the named column.</summary>
                    /// <param name="colname" type="String">Name of the column from which to extract all values.</param>
                    /// <returns type="Array">Returns an array of non-null, non-empty, distinct values extracted from the column.Values are sorted asc.</returns>
                    /// </signature>
                    try {
                        if (isNotString(colname)) {
                            //TODO : log
                            return [];
                        }

                        if (isNullOrUndefined(jqGrid.originalData)) {
                            vpGrid.logError({
                                message: "Cannot get values in column '" + colname + "' because jqGrid.originalData array is not found."
                            });
                        }

                        if (isNotArray(jqGrid.originalData)) {
                            vpGrid.logError({
                                message: "Cannot get values in column '" + colname + "' because jqGrid.originalData is not an array of objects."
                            });
                        }

                        var internalData = jqGrid.getData();
                        var data = internalData.originalData;
                        if (jqGrid.hasLoaded === true) {
                            data = internalData.localData;
                        }
                        
                        if (data.isEmpty()) {
                            data = jqGrid.originalData;
                        }

                        if (data.isEmpty()) {
                            return [];
                        }

                        var colValues = [];
                        var itemCount = data.length;

                        for (var i = 0; i < itemCount; i++) {
                            var dtoObject = data[i];
                            var propertyValue = dtoObject[colname];
                            if (isNullOrUndefined(propertyValue)) {
                                continue;
                            }
                            colValues.push(propertyValue);
                        }

                        var distinctValues = colValues.toUnique();
                        distinctValues = distinctValues.removeEmptyEntries();
                        if (distinctValues.isEmpty()) {
                            return [];
                        }

                        //try get the locale
                        var currentCulture = vpGrid.currentCulture();
                        var sortedValues = distinctValues.sort(function (a, b) {
                            try {
                                if (a.localeCompare) {
                                    return a.localeCompare(b, currentCulture, { sensitivity: "base", numeric : true });
                                }
                                var a1 = a.toLowerCase();
                                var b1 = b.toLowerCase();
                                if (a1 === b1) return 0;
                                if (a1 > b1) return 1;
                                return -1;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                        return sortedValues;

                    } catch (e) {
                        vpGrid.logException(e);
                        return [];
                    }

                }


                jqGrid.colValuesFromDataArray = function (colname, data) {
                    /// <signature>
                    /// <summary>Get all distinct values (from input data) which are not null or empty from the named column.</summary>
                    /// <param name="colname" type="String">Name of the column from which to extract all values.</param>
                    /// <param name="data" type="Array">Array of literal objects from which to extract all values.
                    ///                     This method performs the following query : from o in data select o[columname]
                    /// </param>
                    /// <returns type="Array">Returns an array of non-null, non-empty, distinct values extracted from the data array.
                    ///     Values are sorted asc.
                    /// </returns>
                    /// </signature>
                    try {
                        if (isNotString(colname)) {
                            //TODO : log
                            return [];
                        }

                        if (isNotArray(data)) {
                            vpGrid.logError({
                                functionName: "jqGrid.colValuesFromDataArray",
                                message: "Cannot get values in column '" + colname + "' because input data is not an array of objects."
                            });
                        }

                        if (data.isEmpty()) {
                            return [];
                        }

                        var colValues = [];
                        var itemCount = data.length;

                        for (var i = 0; i < itemCount; i++) {
                            var rowObject = data[i];
                            var propertyValue = rowObject[colname];
                            if (isNullOrUndefined(propertyValue)) {
                                continue;
                            }
                            colValues.push(propertyValue);
                        }

                        var distinctValues = colValues.toUnique();
                        distinctValues = distinctValues.removeEmptyEntries();
                        if (distinctValues.isEmpty()) {
                            return [];
                        }

                        var sortedValues = distinctValues.sort();

                        return sortedValues;

                    } catch (e) {
                        vpGrid.logException(e);
                        return [];
                    }

                }

                

                function onDataReceived(eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onDataReceived, vpGrid, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onDataReceived",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.data)) {
                            eventArgs.data = eventArgsCopy.data;
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onUpdatedDataReceived(eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onUpdatedDataReceived, vpGrid, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onUpdatedDataReceived",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onInsertedDataReceived(eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onInsertedDataReceived, vpGrid, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onInsertedDataReceived",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }



                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }


                function onGridLoaded(eventArgs) {
                    try {
                        //// make a backup copy of eventArgs
                        //var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onGridLoaded, vpGrid, eventArgs);

                        //// check possible misbehavior from listeners
                        //if (isNullOrUndefinedOrEmpty(eventArgs)) {
                        //    vpGrid.logError({
                        //        functionName: "onInsertedDataReceived",
                        //        message: "eventArgs object corrupted by listener",
                        //        info: "eventArgs object is reverted to its original state"
                        //    });
                        //    $.extend(eventArgs, eventArgsCopy);
                        //    return;
                        //}



                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }



                jqGrid.loadDataComplete = function (xhr, textStatus) {
                    try {
                        //TODO : check if the grid is empty (because of no data from server)

                        //check if an error has occured
                        if (xhr && xhr.status !== 200) {
                            hideLoadingMessage();
                            showErrorMessageOnLoad();
                            return;
                        }

                        jqGrid.hasReceivedDataFromRemote = true;

                        //TODO : refactor with executeAsync
                        setTimeout(function () {
                            try {
                                hideLoadingMessage();
                                ////Show message in grid when no data loaded
                                //if (jqGrid.isEmpty()) {
                                //    showEmptyMessageOnLoad();
                                //    return;
                                //}

                                //hideEmptyMessageOnLoad();

                            } catch (e) {
                                vpGrid.logException(e);
                            }

                        }, 1000);


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.loadData = function (timelineExecutionCallback,params) {
                    try {
                        //step -1 : setup signals variables to handle cancelation of the asynchronous grid loading
                        jqGrid.hasLoaded = false;
                        jqGrid.cancelLoad = false;
                        jqGrid.loadIsCanceled = false;
                        jqGrid.hasReceivedDataFromRemote = false;

                        //step 0 : show modal dialog loading
                        hideItemsCountStatus();
                        showLoadingMessage();

                        //step1 : gather all remote filters declared on the page
                        var data = jqGrid.remoteFilters();

                        //step1bis : gather all parameters from the Query String 
                        var dataFromQueryString = jqGrid.getQueryStringData();
                        extendOrMerge(data, dataFromQueryString);

                        //gather additional parameters when this method is called by vpGrid.reloadGrid()
                        extendOrMerge(data, params);

                        //step2 : fetch data on remote server
                        var ajaxOptions = {
                            cache: false,
                            type: "GET",
                            dataType: "json",
                            success: jqGrid.loadDataFromWebResponse,
                            complete: function (xhr, textStatus) {
                                try {
                                    jqGrid.loadDataComplete(xhr, textStatus);

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                                finally {
                                    // continue timeline execution
                                    if (isFunction(timelineExecutionCallback)) {
                                        timelineExecutionCallback();
                                    }
                                    
                                }
                            }
                        }

                        //get url to be requested
                        var crudOperations = vpGrid.options.crudOptions;
                        if (isNullOrUndefinedOrEmpty(crudOperations)) {
                            vpGrid.logError({
                                message: "CRUD operations are not defined in the vpGrid Options object. The grid cannot be loaded."
                            });
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(crudOperations.read)) {
                            vpGrid.logError({
                                message: "CRUD operation Read is not defined in the vpGrid Options object. The grid cannot be loaded."
                            });
                            return;
                        }

                        var requestUrl = crudOperations.read;
                        ajaxOptions.url = requestUrl;

                        if (isNotNullOrUndefinedOrEmpty(data)) {
                            ajaxOptions.data = data;
                        }

                        $.extend(ajaxOptions, vpGridAjaxOptions);

                        //TODO : raise event to enable listeners inspect and/or modify ajaxOptions

                        $.ajax(ajaxOptions);


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                var reloadDataCallsCounter = 0; 
                jqGrid.reloadData = function (timelineExecutionCallback,params) {
                    /// <signature>
                    /// <summary>Reload data from server into the grid</summary>
                    /// <param name="params" type="Object">Literal object that will be sent to the remote server when calling the CRUD Url. 
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (jqGrid.hasLoaded === true) {
                            reloadDataCallsCounter = 0;
                            jqGrid.loadData(timelineExecutionCallback, params);
                            return;
                        }

                        if (jqGrid.cancelLoad === true && jqGrid.loadIsCanceled === false) {
                            //TODO : add counter to force relaod after a certain period of time
                            reloadDataCallsCounter += 1;
                            if (reloadDataCallsCounter > 1000) {
                                //this method is called too many times
                                // stop processing to avoid infinite loop
                                vpGrid.logError({
                                    functionName: "reloadData",
                                    message: "Method is aborted to avoid infinite loop."
                                });
                                return;
                            }
                            setTimeout(function () {
                                jqGrid.reloadData(timelineExecutionCallback,params)
                            }, 10);
                            return;
                        }

                        if (jqGrid.cancelLoad === true && jqGrid.loadIsCanceled === true) {
                            jqGrid.loadData(timelineExecutionCallback, params);
                            return;
                        }

                        // there is a current loading process : abort it and wait for the canceled signal
                        jqGrid.cancelLoad = true;
                        jqGrid.loadIsCanceled = false;
                        setTimeout(function () {
                            jqGrid.reloadData(timelineExecutionCallback,params)
                        }, 10);
                        

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.showProgressAsPercentage = function (element, currentValue, maxValue) {
                    /// <signature>
                    /// <summary>Insert in the DOM element a percentage value of the progress</summary>
                    /// <param name="element" type="Object">DOM element in which to inject the percentage value</param>
                    /// <param name="currentValue" type="Integer">Current value of the progress</param>
                    /// <param name="maxValue" type="Integer">Max value of the progress</param>
                    /// <returns type="Void"></returns>
                    /// </signature>
                    try {
                        var jqElement = $(element);
                        if (jqElement.notFound()) {
                            return;
                        }

                        var percentage = Math.floor((currentValue / maxValue) * 100);
                        jqElement.html(percentage + ' %' );

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.loadDataFromWebResponse = function (response) {
                    try {
                        if (isNullOrUndefinedOrEmpty(response)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadDataFromWebResponse",
                                message: "Server response is null or undefined.",
                                info: "Check if the server is up and running. Check also if the crud options are correctly configured when calling vpGrid.init function."
                            });
                            jqGrid.hasLoaded = true;
                            return;
                        }

                        //TODO : raise event so that listeners can inspect and/or modify response object

                        if (isNullOrUndefined(response.data)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadDataFromWebResponse",
                                message: "response.data object is null or undefined.",
                                info: "response.data is forced to be an empty array."
                            });
                            response.data = [];
                        }

                        var receivedData = response.data;
                        
                        //raise event so that listeners can inspect and/or modify response data
                        var eventArgs = {
                            data: receivedData
                        }
                        onDataReceived(eventArgs);
                        var data = eventArgs.data;
                        var itemCount = data.length;

                        // get the jqGrid host table
                        var jqGridHost = jqGrid.host();

                        //clear grid content
                        jqGridHost.jqGrid('clearGridData', true);

                        //set number of rows in jqGrid
                        var gridOptions = {
                            rowNum: itemCount
                        };
                        jqGridHost.jqGrid('setGridParam', gridOptions);

                        //keep track of received data 
                        jqGrid.originalData = data.duplicate();

                        //save total item count
                        jqGrid.totalItemCount = itemCount;


                        //check for empty grid
                        if (itemCount === 0) {
                            jqGrid.hasLoaded = true;

                            //TODO : raise event onGridLoaded
                            var eventArgs = {};
                            onGridLoaded(eventArgs);

                            hideDataLoadingStatus();
                            showEmptyMessageOnLoad(response);
                            jqGrid.options.gridComplete();
                            executeAsync(this, showItemsCountStatus, 500, "showItemsCountStatus");
                            return;
                        }

                        // data loading in the grid has been replaced by an asynchronous mechanism
                        // do not delete these commented lines : the are there to compare the synchronous and asynchronous loading of the grid
                        //for (var i = 0; i < itemCount; i++) {
                        //    jqGridHost.jqGrid('addRowData', i + 1, data[i]);
                        //}

                        //get the status span where to inject the progress of the asynchronous calls
                        var progressSelector = 'span[' + vpGrid.HtmlDataTag.UIIdentifier + '=dataLoadingProgress]';
                        var jqProgress = $(progressSelector);
                        showDataLoadingStatus();
                        var progressExists = jqProgress.found();

                        //vpGrid.executeAsyncLoopOnArray(data,
                        //    function (i, item) {
                        //        try {
                        //            this.jqGrid('addRowData2', i + 1, item);

                        //            //show loading progress in the UI
                        //            //vpGrid.showUINotificationAtElement(this[0], "Chargement des données en mémoire", i.toString());
                        //            if (progressExists) {
                        //                jqGrid.showProgressAsPercentage(jqProgress[0], i, itemCount);
                        //            }
                                    
                        //        } catch (e) {
                        //            vpGrid.logException(e);
                        //        }
                        //    },
                        //    jqGridHost);


                        if (jqGrid.userIsFilteringTheGrid() === true) {
                            jqGridHost.jqGrid('addRowDataArrayWithNoRowInsertionInDOM', 1, data,
                            function (value) { //onProgress callback
                                try {
                                    //show loading progress in the UI
                                    //vpGrid.showUINotificationAtElement(this[0], "Chargement des données en mémoire", i.toString());
                                    if (progressExists) {
                                        jqGrid.showProgressAsPercentage(jqProgress[0], value, itemCount);
                                    }
                                } catch (e) {
                                    vpGrid.logException(e);
                                }

                            }, // end onProgress callback
                            function () { // onEnd callback
                                try {
                                    executeAsync(this, function () {
                                        try {
                                                
                                                jqGrid.filterGridFromSearchToolbar();
                                                jqGrid.hasLoaded = true;

                                                hideDataLoadingStatus();
                                                hideEmptyMessageOnLoad();
                                                executeAsync(this, showItemsCountStatus, 500, "showItemsCountStatus");
                                                //raise event onGridLoaded
                                                var eventArgs = {};
                                                onGridLoaded(eventArgs);

                                            } catch (e) {
                                                vpGrid.logException(e);
                                            }
                                        }, 0, "filterGridFromSearchToolbar");
                                   
                                    
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            }, // end onEnd callback
                            function (i, item) { //cancel callback
                                try {
                                    if (jqGrid.cancelLoad === true) {
                                        return true;
                                    }

                                    return false;

                                } catch (e) {
                                    vpGrid.logException(e);
                                    return false;
                                }
                            }, // end cancel callback
                            function () { //onCanceled callback
                                try {
                                    jqGrid.loadIsCanceled = true;
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            } // end onCanceled callback
                            );

                            return;
                        }

                        jqGridHost.jqGrid('addRowDataArray', 1, data,
                            function (value) { //onProgress callback
                                try {
                                    //show loading progress in the UI
                                    //vpGrid.showUINotificationAtElement(this[0], "Chargement des données en mémoire", i.toString());
                                    if (progressExists) {
                                        jqGrid.showProgressAsPercentage(jqProgress[0], value, itemCount);
                                    }
                                } catch (e) {
                                    vpGrid.logException(e);
                                }

                            }, // end onProgress callback
                            function () { // onEnd callback
                                try {
                                    
                                    jqGrid.hasLoaded = true;

                                    //TODO : raise event onGridLoaded
                                    var eventArgs = {};
                                    onGridLoaded(eventArgs);

                                    hideDataLoadingStatus();
                                    hideEmptyMessageOnLoad();
                                    executeAsync(this, showItemsCountStatus, 500, "showItemsCountStatus");
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            },
                            function (i,item) { //cancel callback
                                try {
                                    if (jqGrid.cancelLoad === true) {
                                        return true;
                                    }

                                    return false;
                                    
                                } catch (e) {
                                    vpGrid.logException(e);
                                    return false;
                                }
                            },
                            function () { //onCanceled callback
                                try {
                                    jqGrid.loadIsCanceled = true;
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            }
                        );
                            

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                    finally {
                        // execute handler onGridLoaded
                        //VP.Timesheet.ExecuteAsync(VP.Timesheet.EventHandlers.LoadGridEvents.onGridLoaded);
                    }
                }

                jqGrid.remoteFilters = function () {
                    try {
                        // get root node of vpGrid
                        var jqRootNode = jqGrid.container();
                        if (jqRootNode.notFound()) {
                            //TODO : log


                            return {};
                        }

                        var selector = "[role=" + vpGrid.HtmlRoleAttribute.RemoteDataFilter + "]";
                        var jqElements = jqRootNode.find(selector);

                        if (jqElements.notFound()) {
                            //TODO : log
                            return {};
                        }

                        var filters = {};
                        var elementsCount = jqElements.length;
                        for (var i = 0; i < elementsCount; i++) {
                            var element = jqElements[i];
                            var jqElement = $(element);

                            //get the name of the filter key
                            var filterKey = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.RemoteDataFilterKey, "Filter");
                            var filterName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.RemoteDataFilterName, "");
                            var filterOperator = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.RemoteDataFilterOperator, "eq");
                            var filterValue = jqElement.val();

                            if (isNullOrUndefinedOrEmpty(filterValue)) {
                                // this filter must be ignored
                                continue;
                            }

                            if (filterName.isNullOrEmptyOrWhitespace()) {
                                //this is a simple filter like key=value
                                var filter = {};
                                filter[filterKey] = filterValue;
                                extendOrMerge(filters, filter);
                                continue;
                            }

                            //filter key is a query
                            var query = filterName + " " + filterOperator + " " + filterValue;
                            // check if the key has already been setup as a property
                            var filter = {};
                            filter[filterKey] = query;
                            extendOrMerge(filters, filter);

                        } // end for (var i = 0; i < elementsCount; i++)

                        return filters;

                    } catch (e) {
                        vpGrid.logException(e);
                        return {}
                    }
                }

                jqGrid.colExists = function (colName) {
                    /// <signature>
                    /// <summary>Check if the column with the specified name exists</summary>
                    /// <param name="colname" type="String">Name of the column</param>
                    /// <returns type="Boolean">Returns true if the column exists in jqGrid colModel</returns>
                    /// </signature>
                    try {
                        if (isNotString(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.colExists",
                                message: "Input column name is not a valid string."
                            });
                            return false;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found."
                            });
                            return false;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var cellName = colModel.name;
                            if (colModel.name === colName) {
                                return true;
                            }
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }

                }
                jqGrid.colDoesNotExist = function (colName) {
                    return jqGrid.colExists(colName) === false;
                }

                jqGrid.sumOf = function (colName) {
                    /// <signature>
                    /// <summary>Get the sum of all values from the named column.</summary>
                    /// <param name="colname" type="String">Name of the column from which to extract all values.</param>
                    /// <returns type="Number">Returns the sum of all values in the column. Returns NaN if something goes wrong.</returns>
                    /// </signature>
                    try {
                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.sumOf",
                                message: "Input column name is not a valid column name",
                                info: "The name of the column is case sensitive. Check the name or check the column still exists."
                            });
                            return NaN;
                        }

                        var jqGridHost = jqGrid.host();
                        var result = jqGridHost.jqGrid('getCol', colName, false, 'sum');

                        return result;


                    } catch (e) {
                        vpGrid.logException(e);
                        return NaN;
                    }

                }

                jqGrid.filteredSumOf = function (colName, filter, includeInlineSummaryRows) {
                    /// <signature>
                    /// <summary>Get the sum of all values from the named column.</summary>
                    /// <param name="colname" type="String">Name of the column from which to extract and sum all values.</param>
                    /// <param name="filter" type="Function">function that is called on every row in the grid. Must return a boolean value.</param>
                    ///                 If the filter returns true for the current row, the cell value is summed.
                    ///                 If the filter returns false for the current row, the cell value is discarded (not summed)
                    /// <param name="includeInlineSummaryRows" type="Boolean">Use this flag to filter data rows + inline summary rows</param>
                    /// <returns type="Number">Returns the sum of all values in the column. Returns NaN if something goes wrong.</returns>
                    /// </signature>
                    try {
                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.filteredSumOf",
                                message: "Input column name is not a valid column name",
                                info: "The name of the column is case sensitive. Check the name or check the column still exists."
                            });
                            return NaN;
                        }

                        if (isNotFunction(filter)) {
                            vpGrid.logError({
                                functionName: "jqGrid.filteredSumOf",
                                message: "filter callback is not a valid function",
                                info: "Check that function : '" + filter + "' exists in your code."
                            });
                            return NaN;
                        }

                        var jqGridHost = jqGrid.host();
                        var result = jqGridHost.jqGrid('getFilteredCol', colName, false, 'sum',
                            function (row) {
                                try {
                                    // check if the row is an inline summary row
                                    var jqRow = $(row);
                                    
                                    var dataAttributeValue = jqRow.attr("data-vpgrid-summary-id");
                                    if (dataAttributeValue !== undefined && includeInlineSummaryRows !== true) {
                                        return false;
                                    }

                                    var isSummaryRow = false;
                                    if (dataAttributeValue !== undefined) {
                                        isSummaryRow = true;
                                    }

                                    var rowid = row.id;
                                    if (isNullOrUndefinedOrEmpty(rowid)) {
                                        return false;
                                    }

                                    var rowData = jqGrid.rowData(rowid);
                                    if (isSummaryRow == true) {
                                        rowData = jqGrid.summaryRowData(rowid);
                                    }

                                    var isFiltered = filter.call(this, row, rowData);

                                    if (isFiltered === true) {
                                        return true;
                                    }

                                    return false;

                                } catch (e) {
                                    vpGrid.logException(e);
                                    return false;
                                } // end function (filter callback)
                            });

                        return result;


                    } catch (e) {
                        vpGrid.logException(e);
                        return NaN;
                    }

                }


                jqGrid.asyncFilteredSumOf = function (colName, filter, includeInlineSummaryRows, onEnd) {
                    /// <signature>
                    /// <summary>Get the sum of all values from the named column. Each row is processed asynchronously.</summary>
                    /// <param name="colname" type="String">Name of the column from which to extract and sum all values.</param>
                    /// <param name="filter" type="Function">function that is called on every row in the grid. Must return a boolean value.</param>
                    ///                 If the filter returns true for the current row, the cell value is summed.
                    ///                 If the filter returns false for the current row, the cell value is discarded (not summed)
                    /// <param name="includeInlineSummaryRows" type="Boolean">Use this flag to filter data rows + inline summary rows</param>
                    /// <param name="onEnd" type="Function">function that is called when the sum has been computed on the column. 
                    ///                 The sum value is passed to the onEnd callback as the first parameter.
                    ///             
                    ///</param>
                    /// <returns type="Number">Returns the sum of all values in the column. Returns NaN if something goes wrong.</returns>
                    /// </signature>
                    try {
                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.asyncFilteredSumOf",
                                message: "Input column name is not a valid column name",
                                info: "The name of the column is case sensitive. Check the name or check the column still exists."
                            });
                            return NaN;
                        }

                        if (isNotFunction(filter)) {
                            vpGrid.logError({
                                functionName: "jqGrid.asyncFilteredSumOf",
                                message: "filter callback is not a valid function",
                                info: "Check that function : '" + filter + "' exists in your code."
                            });
                            return NaN;
                        }

                        var jqGridHost = jqGrid.host();
                        jqGridHost.jqGrid('getFilteredColAsync', colName, false, 'sum',
                            function (row) {
                                try {
                                    // check if the row is an inline summary row
                                    var jqRow = $(row);

                                    var dataAttributeValue = jqRow.attr("data-vpgrid-summary-id");
                                    if (dataAttributeValue !== undefined && includeInlineSummaryRows !== true) {
                                        return false;
                                    }

                                    var isSummaryRow = false;
                                    if (dataAttributeValue !== undefined) {
                                        isSummaryRow = true;
                                    }

                                    var rowid = row.id;
                                    if (isNullOrUndefinedOrEmpty(rowid)) {
                                        return false;
                                    }

                                    var rowData = jqGrid.rowData(rowid);
                                    if (isSummaryRow == true) {
                                        rowData = jqGrid.summaryRowData(rowid);
                                    }

                                    var isFiltered = filter.call(this, row, rowData);

                                    if (isFiltered === true) {
                                        return true;
                                    }

                                    return false;

                                } catch (e) {
                                    vpGrid.logException(e);
                                    return false;
                                } // end function (filter callback)
                            },
                            onEnd);


                    } catch (e) {
                        vpGrid.logException(e);
                        return NaN;
                    }

                }

                jqGrid.keyColumnName = function () {
                    /// <signature>
                    /// <summary>Get the name of the column that holds the primary key.
                    ///         -> the primary key column is defined in the column schema with 
                    ///            the data attribute : data-vpgrid-column-type='key'
                    ///</summary>
                    /// <returns type="String">Returns the name of the found column. Returns null if the column is not found.</returns>
                    /// </signature>
                    try {
                        
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName : 'keyColumnName',
                                message: "ColModels not found."
                            });
                            return null;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var colName = colModel.name;
                            if (colModel.isKey) {
                                return colName;
                            }
                        }

                        vpGrid.logError({
                            functionName: 'keyColumnName',
                            message: "The primary key column has not been found.",
                            info : "Check col schema. One column should have the following data attribute : '" + vpGrid.HtmlDataTag.ColumnType + "'='key'."
                        });

                        return null;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }

                }

                jqGrid.deleteActionValidatorColumnName = function () {
                    /// <signature>
                    /// <summary>Get the name of the column that holds the actionValidator info for the action of deleting an item.
                    ///         -> the action validator for deleteItem column is defined in the column schema with 
                    ///            the data attribute : data-vpgrid-column-type="actionValidator"
                    ///                                 data-vpgrid-column-actiontype="deleteItem"
                    ///</summary>
                    /// <returns type="String">Returns the name of the found column. Returns null if the column is not found.</returns>
                    /// </signature>
                    try {

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: 'deleteActionValidatorColumnName',
                                message: "ColModels not found."
                            });
                            return null;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var colName = colModel.name;
                            if (colModel.isDeleteActionValidator) {
                                return colName;
                            }
                        }

                        vpGrid.logError({
                            functionName: 'deleteActionValidatorColumnName',
                            message: "The action validator for deleteItem has not been found.",
                            info: "Check col schema. One column should have the following data attributes : '" + vpGrid.HtmlDataTag.ColumnType + "'='actionValidator', '" + vpGrid.HtmlDataTag.ColumnActionType + "'='deleteItem', "
                        });

                        return null;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }

                }

                jqGrid.updateActionValidatorColumnName = function () {
                    /// <signature>
                    /// <summary>Get the name of the column that holds the actionValidator info for the action of updating an item.
                    ///         -> the action validator for updateItem column is defined in the column schema with 
                    ///            the data attribute : data-vpgrid-column-type="actionValidator"
                    ///                                 data-vpgrid-column-actiontype="updateItem"
                    ///</summary>
                    /// <returns type="String">Returns the name of the found column. Returns null if the column is not found.</returns>
                    /// </signature>
                    try {

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: 'updateActionValidatorColumnName',
                                message: "ColModels not found."
                            });
                            return null;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var colName = colModel.name;
                            if (colModel.isUpdateActionValidator) {
                                return colName;
                            }
                        }

                        vpGrid.logError({
                            functionName: 'updateActionValidatorColumnName',
                            message: "The action validator for updateItem has not been found.",
                            info: "Check col schema. One column should have the following data attributes : '" + vpGrid.HtmlDataTag.ColumnType + "'='actionValidator', '" + vpGrid.HtmlDataTag.ColumnActionType + "'='updateItem', "
                        });

                        return null;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }

                }

                jqGrid.canDeleteRowWithId = function (rowId) {
                    /// <signature>
                    /// <summary>Check if the row with the specified HTML Id can be deleted.</summary>
                    /// <param name="rowId" type="String">HTML id of the table row <tr> element within jqGrid</param>
                    /// <returns type="Boolean">Returns true if the row can be deleted.</returns>
                    /// </signature>
                    try {

                        if (isNotString(rowId)) {
                            vpGrid.logError({
                                functionName: "canDeleteRowWithId",
                                message: "rowId is not a string but is :'" + rowId + "'"
                            });
                            return false;
                        }

                        var dataRow = jqGrid.rowData(rowId);
                        if (jqGrid.canDeleteDataRow(dataRow)) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.canDeleteDataRow = function (dataRow) {
                    /// <signature>
                    /// <summary>Check if the row with the specified input data can be deleted.</summary>
                    /// <param name="dataRow" type="Object">Literal object representing the data of a table row <tr> element within jqGrid</param>
                    /// <returns type="Boolean">Returns true if the row can be deleted.</returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            return true;
                        }

                        // get the name of the column that holds the true/false info about if the row is deletable or not
                        var isDeletableColName = jqGrid.deleteActionValidatorColumnName();

                        if (isNullOrUndefinedOrEmpty(isDeletableColName)) {
                            return true;
                        }

                        if (isNotString(isDeletableColName)) {
                            return true;
                        }

                        //check if the property viewmodel.isDeletable has been sent back by the server
                        var isDeletableValue = dataRow[isDeletableColName];

                        if (isNullOrUndefinedOrEmpty(isDeletableValue)) {
                            // no data sent back by the server : the server does not care
                            return true;
                        }

                        if (isString(isDeletableValue) && isDeletableValue.isNullOrEmptyOrWhitespace()) {
                            // no data sent back by the server : the server does not care
                            return true;
                        }

                        //TODO : implement a real boolean property with specific formatter
                        if (isDeletableValue === "true" || isDeletableValue === true) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.cannotDeleteDataRow = function (dataRow) {
                    return jqGrid.canDeleteDataRow(dataRow) === false;
                }

                jqGrid.canUpdateRowWithId = function (rowId) {
                    /// <signature>
                    /// <summary>Check if the row with the specified HTML Id can be updated. In other words check if the row is read only or not.</summary>
                    /// <param name="rowId" type="String">HTML id of the table row <tr> element within jqGrid</param>
                    /// <returns type="Boolean">Returns true if the row can be updated.</returns>
                    /// </signature>
                    try {

                        if (isNotString(rowId)) {
                            vpGrid.logError({
                                functionName: "canUpdateRowWithId",
                                message: "rowId is not a string but is :'" + rowId + "'"
                            });
                            return false;
                        }

                        var dataRow = jqGrid.rowData(rowId);
                        if (jqGrid.canUpdateDataRow(dataRow)) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.canUpdateDataRow = function (dataRow) {
                    /// <signature>
                    /// <summary>Check if the row with the specified input data can be modified (is not read only).</summary>
                    /// <param name="dataRow" type="Object">Literal object representing the data of a table row <tr> element within jqGrid</param>
                    /// <returns type="Boolean">Returns true if the row can be modified.</returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            return true;
                        }

                        // get the name of the column that holds the true/false info about if the row is deletable or not
                        var isUpdatableColName = jqGrid.updateActionValidatorColumnName();

                        if (isNullOrUndefinedOrEmpty(isUpdatableColName)) {
                            return true;
                        }

                        if (isNotString(isUpdatableColName)) {
                            return true;
                        }

                        //check if the property viewmodel.isDeletable has been sent back by the server
                        var isUpdatableValue = dataRow[isUpdatableColName];

                        if (isNullOrUndefinedOrEmpty(isUpdatableValue)) {
                            // no data sent back by the server : the server does not care
                            return true;
                        }

                        if (isString(isUpdatableValue) && isUpdatableValue.isNullOrEmptyOrWhitespace()) {
                            // no data sent back by the server : the server does not care
                            return true;
                        }

                        
                        //TODO : implement a real boolean property with specific formatter
                        if (isUpdatableValue === "true" || isUpdatableValue === true) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.showUINotification = function (title, message, isPersistent) {
                    try {
                        if (isNullOrUndefinedOrEmpty(message)) {
                            return;
                        }

                        var containerSelector = 'div[id=vpgrid-ui-notification-area]';
                        var jqContainer = $(containerSelector);

                        if (jqContainer.notFound()) {
                            $('<div id="vpgrid-ui-notification-area" />').appendTo(document.body);
                            jqContainer = $(containerSelector);
                        }

                        jqContainer.position();
                        var target = $('.qtip.jgrowl:visible:last');

                        $('<div/>').qtip({
                            overwrite: true,
                            style: {
                                widget: true, // Use the jQuery UI widget classes
                                def: false, // Remove the default styling (usually a good idea, see below)
                                width: 250,
                                classes: 'jgrowl',
                                tip: false
                            },
                            content: {
                                text: message,
                                title: {
                                    text: title,
                                    button: true
                                }
                            },
                            position: {
                                target: [0, 0],
                                container: jqContainer
                            },
                            show: {
                                event: false,
                                ready: true,
                                effect: function () {
                                    $(this).stop(0, 1).animate({ height: 'toggle' }, 400, 'swing');
                                },
                                delay: 0,
                                persistent: isPersistent
                            },
                            hide: {
                                event: false,
                                effect: function (api) {
                                    $(this).stop(0, 1).animate({ height: 'toggle' }, 400, 'swing');
                                }
                            },
                            events: {
                                render: function (event, api) {
                                    if (!api.options.show.persistent) {
                                        $(this).bind('mouseover mouseout', function (e) {
                                            var lifespan = 5000;

                                            clearTimeout(api.timer);
                                            if (e.type !== 'mouseover') {
                                                api.timer = setTimeout(function () { api.hide(e) }, lifespan);
                                            }
                                        })
                                        .triggerHandler('mouseout');
                                    }
                                }
                            }

                        });



                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.getQueryStringData = function () {
                    /// <signature>
                    /// <summary>Get the query string as a literal object</summary>
                    /// <returns type="Object">Returns a literal object from the Query String analysis</returns>
                    /// </signature>
                    try {
                        
                        var data = {};
                        var queryString = document.location.search.substr(1);
                        if (queryString.isNullOrEmptyOrWhitespace()) {
                            return {};
                        }

                        $.each(queryString.split('&'), function (c, q) {
                            try {

                                var query = q.split('=');
                                var key = query[0].toString();
                                if (isNullOrUndefinedOrEmpty(key)) {
                                    //TODO : log
                                    vpGrid.logError({
                                        functionName: "getQueryStringData",
                                        message: "Query string : '" + queryString + "'  is not valid at : '" + q + "'",
                                        info: "this parameter is ignored. Check the query string on the url : '" + document.location + "'"
                                    });
                                    return;
                                }
                                var value = '';

                                if (query[1]) {
                                    value = query[1].toString();
                                }

                                value = value.replace(/\+/g, " ");
                                value = decodeURIComponent(value);

                                data[key] = value;


                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                        return data;

                    } catch (e) {
                        vpGrid.logException(e);
                        return {};
                    }
                }

                jqGrid.isInlineSummaryRow = function (rowId) {
                    /// <signature>
                    /// <summary>Check if the row with the specified HTML Id is an inline summary row.</summary>
                    /// <param name="rowId" type="String">HTML id of the table row <tr> element within jqGrid</param>
                    /// <returns type="Boolean">Returns true if the row is an inline summary row. 
                    ///         Inline summary rows are tagged with the data attribute 'data-vpgrid-summary-id'
                    /// </returns>
                    /// </signature>
                    try {

                        if (isNotString(rowId)) {
                            vpGrid.logError({
                                functionName: "isInlineSummaryRow",
                                message: "rowId is not a string but is :'" + rowId + "'"
                            });
                            return false;
                        }

                        var jqRow = jqGrid.row(rowId);
                        if (jqRow.notFound()) {
                            return false;
                        }

                        var summaryId = jqRow.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.SummaryIdentifier, undefined);
                        if (summaryId) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.deleteInlineSummaryRowsForRow = function (rowId) {
                    /// <signature>
                    /// <summary>Delete the inline summary rows that are bound to the jqGrid row rowid</summary>
                    /// <param name="rowId" type="String">HTML id of the table row <tr> element within jqGrid</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (vpGrid.options.enableInlineSummaryRows === false) {
                            return;
                        }

                        if (isNotString(rowId)) {
                            vpGrid.logError({
                                functionName: "jqGrid.deleteInlineSummaryRowsForRow",
                                message: "rowId is not a string but is :'" + rowId + "'"
                            });
                        }

                        var jqGridHost = jqGrid.host();
                        var inlineSummaryRowsSelector = "tr[role=row][data-vpgrid-summary-for=" + rowId + "]";
                        jqGridHost.find(inlineSummaryRowsSelector).detach();

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.unformatThisValueWithCol = function (input, colName) {
                    /// <signature>
                    /// <summary>Unformat the input value according to the type of the column named colName.
                    ///          If the column type is number/integer/currency : input value is unformatted by using the jqGridOptions.jgrid.formatter object.
                    ///          If the column type is of another type, input value is returned.
                    /// </summary>
                    /// <param name="input" type="String">Value entered by the user in the input field.</param>
                    /// <param name="colName" type="String">Name of the column the User is currently editing.</param>
                    /// <returns type="String">Returns a string.</returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(input)) {
                            // nothing to do
                            return input;
                        }

                        if (isNotString(input)) {
                            vpGrid.logError({
                                functionName: "unformatThisValueWithCol",
                                message: "Input value for column '" + colName + "' is not a valid string : '" + input + "'",
                                info: "Input value is returned."
                            });
                            return input;
                        }

                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "unformatThisValueWithCol",
                                message: "Column named '" + colName + "' does not exists.",
                                info: "The type of the input data cannot determined : input value is returned."
                            });
                            return input;
                        }

                        var colModel = JQGrid.colModelOf(colName);

                        if (colModel.isCurrency) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            var decimalSeparator = colModel.formatoptions.decimalSeparator;
                            var sanitizedValue = input.replaceAll(thousandsSeparator, "");
                            sanitizedValue = sanitizedValue.replaceAll(decimalSeparator, '.');
                            return sanitizedValue;
                        }

                        if (colModel.isNumber) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            var decimalSeparator = colModel.formatoptions.decimalSeparator;
                            var sanitizedValue = input.replaceAll(thousandsSeparator, "");
                            sanitizedValue = sanitizedValue.replaceAll(decimalSeparator, '.');
                            return sanitizedValue;
                        }

                        if (colModel.isInteger) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            var sanitizedValue = input.replaceAll(thousandsSeparator, "");
                            return sanitizedValue;
                        }

                        return input;


                    } catch (e) {
                        vpGrid.logException(e);
                        return input;
                    }
                }

            } catch (e) {
                vpGrid.logException(e);
            }
            finally {
                return jqGrid;
            }

        })();

        // end jqGrid layer

        // vpGrid public interface
        vpGrid.currentContainer = function () {
            try {
                var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridContainer + "]";
                var jqElement = $(selector);
                if (jqElement.notFound()) {
                    vpGrid.logError({
                        message: "no container div found (<div role='" + vpGrid.HtmlRoleAttribute.vpGridContainer + "'>" + ") found on page"

                    });
                    return $(null);
                }
                return jqElement;

            } catch (e) {
                vpGrid.logException(e);
                return $(null);
            }

        }

        vpGrid.totalItemCount = function () {
            try {
                var itemCount = JQGrid.totalItemCount;
                return itemCount;

            } catch (e) {
                vpGrid.logException(e);
                return 0;
            }
        }

        vpGrid.filteredItemCount = function () {
            try {
                var itemCount = JQGrid.filteredItemCount;
                return itemCount;

            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.sumOf = function (colName) {
            /// <signature>
            /// <summary>Get the sum of all values from the named column.</summary>
            /// <param name="colname" type="String">Name of the column on which to apply the sum operation.</param>
            /// <returns type="Number">Returns the sum of all values in the column. Returns NaN if something goes wrong.</returns>
            /// </signature>
            try {
                var result = JQGrid.sumOf(colName);
                return result;

            } catch (e) {
                vpGrid.logException(e);
                return NaN;
            }
        }

        vpGrid.filteredSumOf = function (colName, filter, includeInlineSummaryRows) {
            /// <signature>
            /// <summary>Get the sum of all values from the named column and from the rows that are filtered by the filter callback</summary>
            /// <param name="colname" type="String">Name of the column on which to apply the filtered sum operation.</param>
            /// <param name="filter" type="Function">function that is called on every row in the grid. Must return a boolean value.
            ///                 If the filter returns true for the current row, the cell value is summed.
            ///                 If the filter returns false for the current row, the cell value is discarded (not summed).
            ///                 The filter must have the following signature : 
            ///                                 function(row, rowData) {
            ///                                     row = html table row element within the grid.
            ///                                     rowData = literal object that represents the HTML row
            ///                                     Do some test on the row and/or on the content of rowData
            ///                                     return true; // the cell value is added to the sum
            ///                                     return false; // the cell value is not added
            ///                                 }
            /// </param>
            /// <param name="includeInlineSummaryRows" type="Boolean">Use this flag to filter data rows + inline summary rows</param>
            /// <returns type="Number">Returns the sum of all values in the column of the filtered rows. Returns NaN if something goes wrong.</returns>
            /// </signature>
            try {
                var result = JQGrid.filteredSumOf(colName, filter, includeInlineSummaryRows);
                return result;

            } catch (e) {
                vpGrid.logException(e);
                return NaN;
            }
        }

        vpGrid.asyncFilteredSumOf = function (colName, filter, includeInlineSummaryRows, onEnd) {
            /// <signature>
            /// <summary>Get the sum of all values from the named column and from the rows that are filtered by the filter callback.
            ///          Each row is processed asynchronously.
            /// </summary>
            /// <param name="colname" type="String">Name of the column on which to apply the filtered sum operation.</param>
            /// <param name="filter" type="Function">function that is called on every row in the grid. Must return a boolean value.
            ///                 If the filter returns true for the current row, the cell value is summed.
            ///                 If the filter returns false for the current row, the cell value is discarded (not summed).
            ///                 The filter must have the following signature : 
            ///                                 function(row, rowData) {
            ///                                     row = html table row element within the grid.
            ///                                     rowData = literal object that represents the HTML row
            ///                                     Do some test on the row and/or on the content of rowData
            ///                                     return true; // the cell value is added to the sum
            ///                                     return false; // the cell value is not added
            ///                                 }
            /// </param>
            /// <param name="includeInlineSummaryRows" type="Boolean">Use this flag to filter data rows + inline summary rows</param>
            /// <param name="onEnd" type="Function">function that is called when the sum has been computed on the column. 
            ///                 The sum value is passed to the onEnd callback as the first parameter.
            ///             
            ///</param>
            /// <returns type="Number">Returns the sum of all values in the column of the filtered rows. Returns NaN if something goes wrong.</returns>
            /// </signature>
            try {
                JQGrid.asyncFilteredSumOf(colName, filter, includeInlineSummaryRows, onEnd);
               
            } catch (e) {
                vpGrid.logException(e);
                return NaN;
            }
        }


        vpGrid.cellValue = function (rowid,colName) {
            /// <signature>
            /// <summary>Get the value of the cell located in a specific row and in a specific column.</summary>
            /// <param name="rowid" type="String">The id of the row (DOM id) where the cell is located</param>
            /// <param name="colname" type="String">Name of the column where the cell is located.</param>
            /// <returns type="Number">Returns the value in native format.</returns>
            /// </signature>
            try {
                var result = JQGrid.cellValue(rowid, colName);
                return result;

            } catch (e) {
                vpGrid.logException(e);
                return NaN;
            }
        }

        vpGrid.addNewItem = function (event,pos) {
            /// <signature>
            /// <summary>Insert a new row in the grid. Data is read from the current <form> DOM element.</summary>
            /// <param name="pos" type="String">Position of insertion. Valid values are : 'last' and 'first'</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                var jqForm = $(this).closest('div.form-vpgrid-modal-dialog');
                var validationResult = jqForm.validateThisForm();
                if (isNullOrUndefinedOrEmpty(validationResult)) {
                    //TODO : log
                    return;
                }

                if (validationResult.isValid) {
                    jqForm.insertNewRowFromThisForm(pos);
                    $(this).closest('div[role=vpgrid-modal-dialog]').dialog('close');
                    return;
                }

                jqForm.showValidationErrorsOnThisForm(validationResult);
                
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.updateItem = function (event, params) {
            /// <signature>
            /// <summary>Update an existing row in the grid. Data is read from the current <form> DOM element.</summary>
            /// <param name="event" type="Object">Literal object passed by the click event</param>
            /// <param name="params" type="String">Literal object to be merged to the updated row. 
            ///         This literal object will be injected in the ajax call to enable server to process custom updates.
            /// </param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                var jqForm = $(this).closest('div.form-vpgrid-modal-dialog');
                var validationResult = jqForm.validateThisForm();
                if (isNullOrUndefinedOrEmpty(validationResult)) {
                    //TODO : log
                    return;
                }

                if (validationResult.isValid) {
                    jqForm.updateRowFromThisForm(params);
                    $(this).closest('div[role=vpgrid-modal-dialog]').dialog('close');
                    return;
                }

                jqForm.showValidationErrorsOnThisForm(validationResult);

            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.insertNewRow = function (dataRow, pos) {
            /// <signature>
            /// <summary>Insert a new row in the grid</summary>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <param name="pos" type="String">Position of insertion. Valid values are : 'last' and 'first'</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                
                //check if deleteActionValidator has been setup
                var isDeletableColName = JQGrid.deleteActionValidatorColumnName();
                if (isNotNullOrUndefinedOrEmpty(isDeletableColName)) {
                    dataRow[isDeletableColName] = true;
                }

                //check if updateActionValidator (isUpdatable) has been setup
                var isUpdatableColName = JQGrid.updateActionValidatorColumnName();
                if (isNotNullOrUndefinedOrEmpty(isUpdatableColName)) {
                    dataRow[isUpdatableColName] = true;
                }

                //Gather all parameters from the Query String 
                var dataFromQueryString = JQGrid.getQueryStringData();
                extendOrMerge(dataRow, dataFromQueryString);

                JQGrid.insertNewRow(dataRow, pos);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.updateRow = function (dataRow, params) {
            /// <signature>
            /// <summary>Update an exisintg row in the grid</summary>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <param name="params" type="String">Literal object to be merged to the updated row. 
            /// <returns type="void"></returns>
            /// </signature>
            try {
                var customDataRow = $.extend({}, dataRow, params);
                JQGrid.options.updateRowWithFormData(customDataRow);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.insertNewRowAfterSelected = function (dataRow) {
            /// <signature>
            /// <summary>Insert a new row in the grid after the currently selected row.</summary>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.insertNewRowAfterSelected(dataRow);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.insertInlineSummaryRowAfterSelected = function (dataRow) {
            /// <signature>
            /// <summary>Insert a new inline summary row in the grid after the currently selected row.</summary>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.insertInlineSummaryRowAfterSelected(dataRow);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.insertInlineSummaryRowAfter = function (rowid, dataRow, summaryRowidPrefix) {
            /// <signature>
            /// <summary>Insert a new inline summary row in the grid after the row with id rowid.</summary>
            /// <param name="rowid" type="String">Dom id of the row after which to insert the summary row.</param>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be created. 
            ///             If not defined this parameter will receive the value : 'summaryAfter'
            ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
            ///             The data attribute "data-vpgrid-summary-id" will be automatically injected on the summary row :
            ///                     data-vpgrid-summary-id=summaryRowidPrefix
            ///                     -> this will be possible to create a summary row in the footer that is the sum of only inline summary rows with that data tag value
            /// </param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.insertInlineSummaryRowAfter(rowid, dataRow, summaryRowidPrefix);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.insertInlineSummaryRowBefore = function (rowid, dataRow, summaryRowidPrefix) {
            /// <signature>
            /// <summary>Insert a new inline summary row in the grid before the row with id rowid.</summary>
            /// <param name="rowid" type="String">Dom id of the row before which to insert the summary row.</param>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be created. 
            ///             If not defined this parameter will receive the value : 'summaryBefore'
            ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
            ///             The data attribute "data-vpgrid-summary-id" will be automatically injected on the summary row :
            ///                     data-vpgrid-summary-id=summaryRowidPrefix
            ///                     -> this will be possible to create a summary row in the footer that is the sum of only summary rows with that data tag value
            /// </param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.insertInlineSummaryRowBefore(rowid, dataRow, summaryRowidPrefix);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.updateInlineSummaryRowAfter = function (rowid, dataRow, summaryRowidPrefix) {
            /// <signature>
            /// <summary>Update an existing inline summary row in the grid after the row with id rowid.</summary>
            /// <param name="rowid" type="String">Dom id of the row after which to insert the summary row.</param>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be updated. 
            ///             If not defined this parameter will receive the value : 'summaryAfter'
            ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
            ///             The data attribute "data-vpgrid-summary-id" will be automatically injected on the summary row :
            ///                     data-vpgrid-summary-id=summaryRowidPrefix
            ///                     -> this will be possible to create a summary row in the footer that is the sum of only summary rows with that data tag value
            /// </param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.updateInlineSummaryRowAfter(rowid, dataRow, summaryRowidPrefix);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.updateInlineSummaryRowBefore = function (rowid, dataRow, summaryRowidPrefix) {
            /// <signature>
            /// <summary>Update an existing inline summary row in the grid before the row with id rowid.</summary>
            /// <param name="rowid" type="String">Dom id of the row before which to update the summary row.</param>
            /// <param name="dataRow" type="Object">Literal object containing column values to show in the summary row. Each property of this object must match a column name.</param>
            /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be updated. 
            ///             If not defined this parameter will receive the value : 'summaryBefore'
            ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
            ///             The data attribute "data-vpgrid-summary-id" will be automatically injected on the summary row :
            ///                     data-vpgrid-summary-id=summaryRowidPrefix
            ///                     -> this will be possible to create a summary row in the footer that is the sum of only summary rows with that data tag value
            /// </param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.updateInlineSummaryRowBefore(rowid, dataRow, summaryRowidPrefix);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.deleteCurrentRow = function (event) {
            /// <signature>
            /// <summary>Event handler that deletes the currently selected row in the grid.</summary>
            /// <param name="event" type="Object">Literal object passed by the click event</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.deleteCurrentRow();
                vpGrid.closeModalDialog(event);

            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.tryFindModalDialogByName = function (modalDialogName) {
            /// <signature>
            /// <summary>Find the jquery-ui modal dialog from its name. The name should be setup as a data attribute on the div dialog : 
            ///         <div role="vpgrid-modal-dialog"
            ///                 title="Suppression d'un item"
            ///                 class="vpgrid-hidden vpgrid-container vpgrid-modal-dialog"
            ///                 data-vpgrid-dialog-id="modalDialogName">
            ///          </div>   
            ///</summary>
            /// <param name="modalDialogName" type="String">Value of the 'data-vpgrid-dialog-id' data attribute on the div dialog.</param>
            /// <returns type="Object">Returns the found div dialog dom element. If the div dialog is not found, the function returns undefined.</returns>
            /// </signature>
            try {
                if (isNotString(modalDialogName)) {
                    vpGrid.logError({
                        functionName: "tryFindModalDialogByName",
                        message: "The name of the modal dialog is not a valid string. It's value is : '" + modalDialogName + "'"
                    });
                    return undefined;
                }

                var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridModalDialog + "]";
                var jqElements = $(selector);

                if (jqElements.notFound()) {
                    vpGrid.logError({
                        functionName: "tryFindModalDialogByName",
                        message: "Div Modal Dialog not found with selector : '" + selector + "'",
                        info: "Check that it exists a div with atrribute role='vpgrid-modal-dialog' and data attribute data-vpgrid-dialog-id='" + modalDialogName + "'"
                    });
                    return undefined;
                }

                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, "");
                    if (dialogId === modalDialogName) {
                        return element;
                    }
                } // end for (var i = 0; i < elementsCount; i++)


                vpGrid.logError({
                    functionName: "tryFindModalDialogByName",
                    message: "Div Modal Dialog not found.",
                    info: "Check that it exists a div with atrribute role='vpgrid-modal-dialog' and data attribute data-vpgrid-dialog-id='" + modalDialogName + "'"
                });

                return undefined;


            } catch (e) {
                vpGrid.logException(e);
                return undefined;
            }
        }

        vpGrid.closeModalDialog = function (event) {
            /// <signature>
            /// <summary>Event handler that closes the modal dialog window targeted by the input parameter event.</summary>
            /// <param name="event" type="Object">Literal object passed by the click event</param>
            /// </signature>
            try {
                if (isNullOrUndefinedOrEmpty(event)) {
                    //TODO : log
                    return;
                }

                if (isNullOrUndefinedOrEmpty(event.target)) {
                    vpGrid.logError({
                        message: "input parameter event is not a valid object : target property not found or not valid",
                        functionName: "vpGrid.closeModalDialog",
                        info: "Check that vpGrid.closeModalDialog is called by a click event on a DOM element."

                    });
                    return;
                }

                var target = event.target;
                var elementSelector = "div[role=vpgrid-modal-dialog]";
                var jqElement = $(target).closest(elementSelector);

                if (jqElement.notFound()) {
                    vpGrid.logError({
                        message: "Selector not found : '" + elementSelector + "'",
                        functionName: "vpGrid.closeModalDialog",
                        info: "Check that '" + elementSelector + "'" + " is parent of element :\n" + outerHtml(target)

                    });
                    return;
                }

                jqElement.dialog('close');


            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.openModalDialog = function (event,modalDialogId) {
            /// <signature>
            /// <summary>Event handler that opens the modal dialog window targeted by modalDialogId.</summary>
            /// <param name="event" type="Object">Literal object passed by the click event</param>
            /// <param name="modalDialogId" type="String">value of the data attribute 'data-vpgrid-dialog-id'</param>
            /// </signature>
            try {
                if (isNullOrUndefinedOrEmpty(event)) {
                    //TODO : log
                    return;
                }

                if (isNullOrUndefinedOrEmpty(event.target)) {
                    vpGrid.logError({
                        message: "input parameter event is not a valid object : target property not found or not valid",
                        functionName: "vpGrid.closeModalDialog",
                        info: "Check that vpGrid.openModalDialog is called by a click event on a DOM element."

                    });
                    return;
                }

                if (isNotString(modalDialogId)) {
                    vpGrid.logError({
                        message: "input parameter modalDialogId is not a valid string : '" + modalDialogId + "'",
                        functionName: "vpGrid.openModalDialog",
                        info: "Check that 'data-vpgrid-handlers' data attribute is correctly setup on the clicked button."
                    });
                    return;
                }
                
                var elementSelector = "div[role=vpgrid-modal-dialog][data-vpgrid-dialog-id=" + modalDialogId + "]";
                var jqElement = $(elementSelector);

                if (jqElement.notFound()) {
                    vpGrid.logError({
                        message: "Selector not found : '" + elementSelector + "'",
                        functionName: "vpGrid.openModalDialog",
                        info: "Check that '" + elementSelector + "' exists in the web page."

                    });
                    return;
                }

                jqElement.openClientSideDialog();


            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.openModalDialogWithSelectedItem = function (event, modalDialogId,position) {
            /// <signature>
            /// <summary>Event handler that opens the modal dialog window targeted by modalDialogId. 
            ///         Input controls on this dialog are filled with the data coming from the selected item in the grid.
            ///         The databinding is done through the data-tag attribute : data-vpgrid-column-name
            /// </summary>
            /// <param name="event" type="Object">Literal object passed by the click event</param>
            /// <param name="modalDialogId" type="String">value of the data attribute 'data-vpgrid-dialog-id'</param>
            /// </signature>
            try {
                if (isNullOrUndefinedOrEmpty(event)) {
                    //TODO : log
                    return;
                }

                if (isNullOrUndefinedOrEmpty(event.target)) {
                    vpGrid.logError({
                        message: "input parameter event is not a valid object : target property not found or not valid",
                        functionName: "vpGrid.openModalDialogWithSelectedItem",
                        info: "Check that vpGrid.openModalDialogWithSelectedItem is called by a click event on a DOM element."

                    });
                    return;
                }

                if (isNotString(modalDialogId)) {
                    vpGrid.logError({
                        message: "input parameter modalDialogId is not a valid string : '" + modalDialogId + "'",
                        functionName: "vpGrid.openModalDialogWithSelectedItem",
                        info: "Check that 'data-vpgrid-handlers' data attribute is correctly setup on the clicked button."
                    });
                    return;
                }

                var elementSelector = "div[role=vpgrid-modal-dialog][data-vpgrid-dialog-id=" + modalDialogId + "]";
                var jqElement = $(elementSelector);

                if (jqElement.notFound()) {
                    vpGrid.logError({
                        message: "Selector not found : '" + elementSelector + "'",
                        functionName: "vpGrid.openModalDialogWithSelectedItem",
                        info: "Check that '" + elementSelector + "' exists in the web page."

                    });
                    return;
                }

                jqElement.openClientSideDialogWithSelectedItem(position);


            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.openServerSideDialogWithSelectedItem = function (event, eventArgs) {
            /// <signature>
            /// <summary>Event handler that opens an external web page as a modal dialog window targeted by modalDialogId. 
            ///         The databinding is done through the data-tag attribute : data-vpgrid-column-name
            /// </summary>
            /// <param name="event" type="Object">Literal object passed by the click event</param>
            /// <param name="eventArgs" type="Object">Literal object that has been deserialized from the data attribute data-vpgrid-handlers.
            ///             eventArgs has the following signature: 
            ///                 {
            ///                     dialogId : vpgrid id of the UI-Dialog to open,
            ///                     sizeRatio : number between 0.1 and 0.9 that is a ratio between the size of the UI dialog and the browser window size.
            ///                 }
            /// </param>
            /// </signature>
            try {
                if (isNullOrUndefinedOrEmpty(event)) {
                    //TODO : log
                    return;
                }

                if (isNullOrUndefinedOrEmpty(eventArgs)) {
                    vpGrid.logError({
                        message: "eventArgs parameter is not a valid object.",
                        functionName: "vpGrid.openServerSideDialogWithSelectedItem",
                        info: "Check that the DOM element has the following a data attribute data-vpgrid-handlers that is correctly configured :\n" + outerHtml(jqElement[0])

                    });
                    return;
                }

                if (isNullOrUndefinedOrEmpty(event.target)) {
                    vpGrid.logError({
                        message: "input parameter event is not a valid object : target property not found or not valid",
                        functionName: "vpGrid.openServerSideDialogWithSelectedItem",
                        info: "Check that vpGrid.openModalDialogWithSelectedItem is called by a click event on a DOM element."

                    });
                    return;
                }

                if (isNotString(eventArgs.dialogId)) {
                    vpGrid.logError({
                        message: "input parameter eventArgs.dialogId is not a valid string : '" + eventArgs.dialogId + "'",
                        functionName: "vpGrid.openServerSideDialogWithSelectedItem",
                        info: "Check that 'data-vpgrid-handlers' data attribute is correctly setup on the clicked button."
                    });
                    return;
                }

                var elementSelector = "div[role=vpgrid-modal-dialog][data-vpgrid-dialog-id=" + eventArgs.dialogId + "]";
                var jqElement = $(elementSelector);

                if (jqElement.notFound()) {
                    vpGrid.logError({
                        message: "Selector not found : '" + elementSelector + "'",
                        functionName: "vpGrid.openServerSideDialogWithSelectedItem",
                        info: "Check that '" + elementSelector + "' exists in the web page."

                    });
                    return;
                }

                jqElement.openServerSideDialogWithSelectedItem(eventArgs.position, eventArgs.sizeRatio);


            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.bindDataSourceOnElement = function (element) {
            bindDataSourceOnElement(element);
        }

        vpGrid.getQueryStringData = function () {
            /// <signature>
            /// <summary>Get the query string as a literal object</summary>
            /// <returns type="Object">Returns a literal object from the Query String analysis</returns>
            /// </signature>
            try {

                var data = JQGrid.getQueryStringData();
                return data;

            } catch (e) {
                vpGrid.logException(e);
                return {};
            }
        }

        vpGrid.reloadGrid = function (event, eventArgs) {
            /// <signature>
            /// <summary>Reload the grid without reloading the all page (F5).
            ///         This method executes asynchronously and so returns immediately.
            ///         If you need to execute some business rules when the grid is loaded with all its data,
            ///         you must register to the event onGridLoaded.
            /// </summary>
            /// <param name="event" type="Object">Literal object passed by the event handler when this method is bound to an event handler through the data tag data-vpgrid-handlers</param>
            /// <param name="eventArgs" type="Object">Literal object that has been deserialized from the data attribute data-vpgrid-handlers.
            ///      This literal object that will be sent to the remote server when calling the CRUD Url. 
            /// </param>
            /// <returns type="Void"></returns>
            /// </signature>
            try {
                executeAsync(this, function () {
                    try {
                        var params = eventArgs;
                        if (eventArgs === undefined) {
                            params = event;
                        }

                        if (isString(params)) {
                            var param2 = {}
                            param2[params] = "";
                            params = param2;
                        }

                        //TODO : test params is a literal Object

                        JQGrid.reloadData(function () { }, params);
                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }, 100, "reloadGrid");
                
            } catch (e) {
                vpGrid.logException(e);

            }
        }

        vpGrid.rowData = function (rowid) {
            /// <signature>
            /// <summary>get the data of a table row within jqGrid </summary>
            /// <param name="rowid" type="String">Dom id of the row.</param>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <returns type="Object">Returns a literal object containing column values. Each property of this object matches a column name.
            ///                        Returns null if an exception is thrown.
            /// </returns>
            /// </signature>
            try {
                return JQGrid.rowData(rowid);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.selectedRowData = function () {
            /// <signature>
            /// <summary>get the data of the selected row within jqGrid. The selected row is the one that is checked (when left checkboxes exist) </summary>
            /// <returns type="Object">Returns a literal object containing column values. Each property of this object matches a column name.
            ///                        Returns null if an exception is thrown.
            /// </returns>
            /// </signature>
            try {
                return JQGrid.selectedRowData();
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.sumObjects = function(input1, input2) {
            /// <signature>
            /// <summary>Compute the sum of each matched properties of object literals input1 and input2 </summary>
            /// <param name="input1" type="Object">Literal object</param>
            /// <param name="input2" type="Object">Literal object</param>
            /// <returns type="Object">Returns a new literal object that contains the same properties as input1. If possible each property is the sum of the corresponding property in each input objects.</returns>
            /// </signature>
            try {
                var newObj = {};
                if (isNullOrUndefinedOrEmpty(input1)) {

                    extendOrMerge(newObj, input2);
                    return newObj;
                }

                if (isNullOrUndefinedOrEmpty(input2)) {
                    extendOrMerge(newObj, input1);
                    return newObj;
                }


                for (var p in input1) {
                    newObj[p] = input1[p];
                    if (isNotCustomPropertyOf(input2, p)) {
                        continue;
                    }
                    var temp = [];
                    temp.push(input1[p]);
                    temp.push(input2[p]);

                    newObj[p] = temp.sum();
                }

                return newObj;

            } catch (e) {
                vpGrid.logException(e);
                return {};
            }
        };

        vpGrid.hasLoaded = function () {
            /// <signature>
            /// <summary>Check if data has been loaed in the grid</summary>
            /// <returns type="Boolean">Returns true if data has been loaded in the grid.</returns>
            /// </signature>
            try {
                return JQGrid.hasLoaded;
            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        }

        vpGrid.isEmpty = function () {
            /// <signature>
            /// <summary>Check if the grid is empty</summary>
            /// <returns type="Object">Returns true if the grid shows no data</returns>
            /// </signature>
            try {

                return JQGrid.isEmpty();

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        }

        vpGrid.firstRow = function () {
            /// <signature>
            /// <summary>Get the first row showed in the grid</summary>
            /// <returns type="Object">Returns the found row as a DOM element. Returns null if the grid is empty.</returns>
            /// </signature>
            try {

                return JQGrid.firstRow();

            } catch (e) {
                vpGrid.logException(e);
                return null;
            }
        }

        vpGrid.currentUIModalDialog = function () {
            /// <signature>
            /// <summaryGet the currently opened jQuery UI modal dialog</summary>
            /// <returns type="Object">Returns the DOM element if found. 
            ///     Returns null if no UI dialog is currently opened
            /// </returns>
            /// </signature>
            try {
                var selector = "div.ui-dialog:visible";
                var jqDialog = $(selector);

                if (jqDialog.notFound()) {
                    return null;
                }

                var dialogContentSelector = ".ui-dialog-content";
                var jqContentDialog = jqDialog.find(dialogContentSelector);

                if (jqContentDialog.notFound()) {
                    return null;
                }

                var jqLastDialog = jqContentDialog.last();
                return jqLastDialog[0];

            } catch (e) {
                vpGrid.logException(e);
                return null;
            }
        }

        vpGrid.currentUIModalDialogId = function () {
            /// <signature>
            /// <summaryGet the vpgrid Id of the currently opened jQuery UI modal dialog</summary>
            /// <returns type="String">Returns the content of the data tag  data-vpgrid-dialog-id
            ///     Returns null if no UI dialog is currently opened
            /// </returns>
            /// </signature>
            try {
                var currentModalDialog = vpGrid.currentUIModalDialog();
                if (currentModalDialog == null) {
                    return null;
                }

                var jqDialog = $(currentModalDialog);
                var vpgridId = jqDialog.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, null);

                return vpgridId;

            } catch (e) {
                vpGrid.logException(e);
                return null;
            }
        }

        vpGrid.currentUIModalDialogData = function () {
            /// <signature>
            /// <summaryGet all input fields present in the currently opened jQuery UI modal dialog.
            ///     Only input fields tagged with the data tag 'data-vpgrid-column-name' are extracted.
            /// </summary>
            /// <returns type="Object">Returns a literal object. 
            ///     Each property of this literal object matches a column name, 
            ///     and the value of each property is the content of the correponding input field.
            ///     Returns null if no field found or if something goes wrong
            /// </returns>
            /// </signature>
            try {
                var currentModalDialog = vpGrid.currentUIModalDialog();
                if (currentModalDialog == null) {
                    return null;
                }

                var jqDialog = $(currentModalDialog);
                var dialogData = jqDialog.getGridDataFromThisForm();

                return dialogData;

            } catch (e) {
                vpGrid.logException(e);
                return null;
            }
        }

        vpGrid.deleteRow = function (rowid) {
            /// <signature>
            /// <summary>Delete a row in the grid.</summary>
            /// <param name="rowid" type="String">Dom id of the row to be deleted in the grid.</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.deleteRow(rowid);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.getRowThatHoldsItemWithKey = function (itemKey) {
            /// <signature>
            /// <summary>Get the grid row that holds the item identified by its key itemKey.</summary>
            /// <param name="itemKey" type="String">Key of the item to found in the grid</param>
            /// <returns type="Object">DOM object of the found table row. Returns null if the row is not found.</returns>
            /// </signature>
            try {
                var jqRow = JQGrid.getRowThatHoldsItemWithKey(itemKey);
                if (jqRow.notFound()) {
                    return null;
                }

                return jqRow[0];

            } catch (e) {
                vpGrid.logException(e);
                return null;
            }
        }

        vpGrid.showCol = function (colName) {
            /// <signature>
            /// <summary>Show in the UI the column named colName</summary>
            /// <param name="colName" type="String">Name of the column to show. This name is defined in the colModel of the corresponding column.</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.showCol(colName);

            } catch (e) {
                vpGrid.logException(e);
            }
        }
        vpGrid.hideCol = function (colName) {
            /// <signature>
            /// <summary>Hide in the UI the column named colName</summary>
            /// <param name="colName" type="String">Name of the column to hide. This name is defined in the colModel of the corresponding column.</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.hideCol(colName);

            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.resizeCol = function (colName, width) {
            /// <signature>
            /// <summary>Resize in the UI the column named colName.</summary>
            /// <param name="colName" type="String">Name of the column to resize. This name is defined in the colModel of the corresponding column.</param>
            /// <param name="width" type="Integer">New width of the column</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.resizeCol(colName, width);

            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.renderSummaryRows = function () {
            /// <signature>
            /// <summary>Render or re-render all summary rows. 
            ///          This method will raise the event onSummaryCellRendering for all summary cells in all summary rows.
            ///          Caller must listen to the event  onSummaryCellRendering to handle the rendering of each summary cell.
            ///     
            /// </summary>
            /// <returns type="void"></returns>
            /// </signature>
            try {

                JQGrid.options.renderSummaryRows();

            } catch (e) {
                vpGrid.logException(e);

            }
        }

        vpGrid.getData = function () {
            /// <signature>
            /// <summary>Get all the data arrays stored by vpGrid and by jqGrid.
            ///     This method must be used only for test purpose or for debug purpose
            ///     You should never modify the returned data. 
            /// </summary>
            /// <returns type="Object">Literal object with the following signature
            ///         {
            ///              originalData: -> the data sent by the server
            ///              updatedData:  -> the data that was updated in the grid and needs to be updated on server
            ///              deletedData:  -> the data that was deleted in the grid and needs to be deleted on server
            ///              insertedData: -> the data that was inserted in the grid and needs to be inserted on server
            ///              insertedDataWithValidationErrors : -> the data that was inserted in the grid but not validated
            ///              updatedDataWithValidationErrors : -> the data that was updated in the grid but not validated
            ///              localData:    -> the data used by jqGrid to show items in the grid
            ///              localIndexes: -> key/value collection where key is a row HTML id and value is the index of the corresponding data in localData.
            ///              filteredData: -> the data filtered in the grid
            ///         }
            /// </returns>
            /// </signature>
            try {

                return JQGrid.getData();

            } catch (e) {
                vpGrid.logException(e);
                return null;
            }
        }

        vpGrid.getSchema = function () {
            /// <signature>
            /// <summary>Get the jqGrid col models array.
            ///     This method must be used only for test purpose or for debug purpose
            ///     You should never modify the returned data. 
            /// </summary>
            /// <returns type="Object">Literal object with the following signature
            ///         {
            ///              colTitles: -> string array. Each string is the title column
            ///              colModels: -> array of literal objects. Each object stores the configuration of a column
            ///         }
            /// </returns>
            /// </signature>
            try {

                return JQGrid.getSchema();

            } catch (e) {
                vpGrid.logException(e);
                return null;
            }
        }

        vpGrid.updateInsertDeleteDataOnRemote = function () {
            /// <signature>
            /// <summary>Perform the CRUD operation from the jqGrid.updatedData/deletedData/insertedData arrays
            ///   This method should be called only when the vpGrid option enableAutomaticPropagationOfUpdateInsertDeleteOperations is set to false.
            ///   In other words this method should be called only when the grid was offline and is now online.
            ///</summary>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.updateInsertDeleteDataOnRemote();
            } catch (e) {
                vpGrid.logException(e);
            }
        }


        vpGrid.currentCulture = function () {
            /// <signature>
            /// <summary>Get the current Culture (locale) for this grid
            /// </summary>
            /// <returns type="String">Value of the the locale set in vpGrid options.
            /// </returns>
            /// </signature>
            try {
                var locale = vpGrid.options.locale;
                return locale;

            } catch (e) {
                vpGrid.logException(e);
                return 'en';
            }
        }

        vpGrid.validateDataRow = function (dataRow) {
            /// <signature>
            /// <summary>Validate all fields of the row represented by the input dataRow.</summary>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <returns type="Object">Returns a literal object with the following signature
            ///             {
            ///                 isValid : true|false
            ///                 errors : [] -> array of strings containing all errors in the dataRow
            ///                     each object in the array must have the following signature:
            ///                     {
            ///                         propertyName : string -> name of a column/field = property name in input dataRow
            ///                         message : string -> put here the error message for the specified column/field
            ///                     }
            ///             }
            /// </returns>
            /// </signature>
            try {
                return JQGrid.validateDataRow(dataRow);
            } catch (e) {
                vpGrid.logException(e);
                return null;
            }
        }

        vpGrid.reloadDataRowFromRemote = function (dataRow) {
            /// <signature>
            /// <summary>Trigger an ajax operation to get the content of an existing data row updated by reloading data from server.</summary>
            /// <param name="dataRow" type="Object">Literal object representing a row already loaded in the grid.
            ///                         This literal object contains column values. Each property of this object should match a column name.</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {

                JQGrid.reloadDataRowFromRemote(dataRow);

            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.dataRowToNativeValues = function (dataRow) {
            /// <signature>
            /// <summary>Convert input literal object 
            ///     into another literal object where each property value (generally a string) is converted 
            ///     to a type derived from the type of the corresponding column.
            /// </summary>
            /// <param name="input" type="Object">Literal object representing a data row : {col1:xxx, col2:yyy, ... colN:zzz}</param>
            /// <returns type="Object">Returns a new literal object with same properties where values are converted from string to the native type of the column.
            ///             If conversion fails the original property value is returned</returns>
            /// </signature>
            try {
                return JQGrid.toNativeValues(dataRow);

            } catch (e) {
                vpGrid.logException(e);
                return dataRow;
            }
        }


        // vpGrid initialization
        vpGrid.init = function (options) {

            try {
                var jqContainer = vpGrid.currentContainer();

                if (jqContainer.notFound()) {
                    vpGrid.logError({
                        message: "vpGrid processing is stopped."
                    });
                    return;
                }

                vpGrid.initOptions(options);

                registerPrivateHandlers();

                Behaviors.executeTimeline();

                //prevent window closing if CRUD operations are not completed with server
                window.onbeforeunload = JQGrid.onBeforeUnload;

            } catch (e) {
                vpGrid.logException(e);
            }
        }

        //vpGrid ui notifier
        vpGrid.showUINotification = function (title, message,isPersistent) {
            try {
                if (isNullOrUndefinedOrEmpty(message)) {
                    return;
                }

                var containerSelector = 'div[id=vpgrid-ui-notification-area]';
                var jqContainer = $(containerSelector);

                if (jqContainer.notFound()) {
                    $('<div id="vpgrid-ui-notification-area" />').appendTo(document.body);
                    jqContainer = $(containerSelector);
                }

                var target = $('.qtip.jgrowl:visible:last');

                $('<div/>').qtip({
                    overwrite: true,
                    style: {
                        widget: true, // Use the jQuery UI widget classes
                        def: false, // Remove the default styling (usually a good idea, see below)
                        width: 250,
                        classes: 'jgrowl',
                        tip: false
                    },
                    content: {
                        text: message,
                        title: {
                            text: title,
                            button: true
                        }
                    },
                    position: {
                        target : [0,0],
                        container: jqContainer
                    },
                    show: {
                        event: false,
                        ready: true,
                        effect: function () {
                            $(this).stop(0, 1).animate({ height: 'toggle' }, 400, 'swing');
                        },
                        delay: 0,
                        persistent: isPersistent
                    },
                    hide: {
                        event: false,
                        effect: function (api) {
                            $(this).stop(0, 1).animate({ height: 'toggle' }, 400, 'swing');
                        }
                    },
                    events: {
                        render: function (event, api) {
                            if (!api.options.show.persistent) {
                                $(this).bind('mouseover mouseout', function (e) {
                                    var lifespan = 5000;

                                    clearTimeout(api.timer);
                                    if (e.type !== 'mouseover') {
                                        api.timer = setTimeout(function () { api.hide(e) }, lifespan);
                                    }
                                })
                                .triggerHandler('mouseout');
                            }
                        }
                    }

                });



            } catch (e) {
                vpGrid.logException(e);
            }
        }

        //vpGrid ui notifier
        vpGrid.showUINotificationAtElement = function (element, title, message, options) {
            try {
                if (isNullOrUndefinedOrEmpty(message)) {
                    return;
                }

                var jqElement = $(element);
                var qtipOptions = {
                    overwrite: true,
                    style: {
                        widget: true, // Use the jQuery UI widget classes
                        def: false, // Remove the default styling (usually a good idea, see below)
                        width: 250,
                        tip: true
                    },
                    prerender: true,
                    content: {
                        text: message,
                        title: {
                            text: title,
                            button: false
                        }
                    },
                    position: {
                        my: 'top left',
                        at: 'bottom center',
                        viewport: $(window),
                        //container : $(element),
                        //target: 'mouse',
                        target: $(element),
                        adjust: {
                            mouse: true,
                            scroll: false,
                            x: 5,
                            y: 0
                        }
                    },

                    show: {
                        event: false,
                        ready: true
                        //target: $(element)
                    },
                    hide: {
                        //fixed: true,
                        distance: 30
                    }
                };

                if (isNotNullOrUndefinedOrEmpty(options)) {
                    $.extend(qtipOptions, options);
                }

                //if (jqElement.is("tr")) {
                //    jqElement.find("td[role=gridcell]").first().qtip(qtipOptions);
                //    return;
                //}

                jqElement.qtip(qtipOptions);


            } catch (e) {
                vpGrid.logException(e);
            }
        }

        //end vpGrid initialization

        // end vpGrid interface

    } catch (e) {
        vpGrid.logException(e);
    }
    finally {
        window.vpGrid = vpGrid;
    }
})(this, jQuery);




/* jqGrid extension for inserting inline summary rows inside jqGrid
    Each row may have a summary row placed after and/or before its current position
    Cell editing is automatically disabled for any summary row
*/
(function ($) {
    "use strict";
    $.jgrid = $.jgrid || {};
    $.jgrid.extend({
        addInlineSummaryRowData: function (rowid, rdata, pos, src) {
            //behaves like addRowData to insert a new summary row within the grid itself
            if (!pos) { pos = "last"; }
            var success = false, nm, row, gi, si, ni, sind, i, v, prp = "", aradd, cnm, cn, data, cm, id;
            if (rdata) {
                if ($.isArray(rdata)) {
                    aradd = true;
                    pos = "last";
                    cnm = rowid;
                } else {
                    rdata = [rdata];
                    aradd = false;
                }
                this.each(function () {
                    var t = this, datalen = rdata.length;
                    ni = t.p.rownumbers === true ? 1 : 0;
                    gi = t.p.multiselect === true ? 1 : 0;
                    si = t.p.subGrid === true ? 1 : 0;
                    if (!aradd) {
                        if (rowid !== undefined) { rowid = String(rowid); }
                        else {
                            rowid = $.jgrid.randId();
                            if (t.p.keyIndex !== false) {
                                cnm = t.p.colModel[t.p.keyIndex + gi + si + ni].name;
                                if (rdata[0][cnm] !== undefined) { rowid = rdata[0][cnm]; }
                            }
                        }
                    }
                    cn = t.p.altclass;
                    var k = 0, cna = "", lcdata = {},
                    air = $.isFunction(t.p.afterInsertRow) ? true : false;
                    while (k < datalen) {
                        data = rdata[k];
                        row = [];
                        if (aradd) {
                            try {
                                rowid = data[cnm];
                                if (rowid === undefined) {
                                    rowid = $.jgrid.randId();
                                }
                            }
                            catch (e) { rowid = $.jgrid.randId(); }
                            cna = t.p.altRows === true ? (t.rows.length - 1) % 2 === 0 ? cn : "" : "";
                        }
                        id = rowid;
                        rowid = t.p.idPrefix + rowid;
                        if (ni) {
                            prp = t.formatCol(0, 1, '', null, rowid, true);
                            row[row.length] = "<td role=\"gridcell\" class=\"ui-state-default jqgrid-rownum\" " + prp + ">0</td>";
                        }
                        if (gi) {
                            //v = "<input role=\"checkbox\" type=\"checkbox\"" + " id=\"jqg_" + t.p.id + "_" + rowid + "\" class=\"cbox\"/>";
                            v = "";
                            prp = t.formatCol(ni, 1, '', null, rowid, true);

                            //hdo : inject  data-vpgrid-column-name attribute
                            var prp2 = ' data-vpgrid-column-name="cb"';

                            //row[row.length] = "<td role=\"gridcell\" " + prp + ">" + v + "</td>";
                            row[row.length] = "<td role=\"summarygridcell\" " + prp + prp2 + ">" + v + "</td>";
                        }
                        if (si) {
                            row[row.length] = $(t).jqGrid("addSubGridCell", gi + ni, 1);
                        }
                        for (i = gi + si + ni; i < t.p.colModel.length; i++) {
                            cm = t.p.colModel[i];
                            nm = cm.name;
                            lcdata[nm] = data[nm];
                            v = t.formatter(rowid, $.jgrid.getAccessor(data, nm), i, data);
                            //hdo
                            if (cm.isCheckbox) {
                                v = data[nm];
                            }
                            if (cm.isAction) {
                                v = '';
                            }
                            //

                            //hdo : inject  data-vpgrid-column-name attribute
                            var prp2 = ' data-vpgrid-column-name="' + nm + '"';

                            prp = t.formatCol(i, 1, v, data, rowid, lcdata);
                            //row[row.length] = "<td role=\"summarygridcell\" " + prp + ">" + v + "</td>";
                            row[row.length] = "<td role=\"summarygridcell\" " + prp + prp2 + ">" + v + "</td>";
                        }
                        row.unshift(t.constructTr(rowid, false, cna, lcdata, data, false));
                        row[row.length] = "</tr>";
                        if (t.rows.length === 0) {
                            $("table:first", t.grid.bDiv).append(row.join(''));
                        } else {
                            switch (pos) {
                                case 'last':
                                    $(t.rows[t.rows.length - 1]).after(row.join(''));
                                    sind = t.rows.length - 1;
                                    break;
                                case 'first':
                                    $(t.rows[0]).after(row.join(''));
                                    sind = 1;
                                    break;
                                case 'after':
                                    sind = $(t).jqGrid('getGridRowById', src);
                                    if (sind) {
                                        if ($(t.rows[sind.rowIndex + 1]).hasClass("ui-subgrid")) { $(t.rows[sind.rowIndex + 1]).after(row); }
                                        else { $(sind).after(row.join('')); }
                                        sind = sind.rowIndex + 1;
                                    }
                                    break;
                                case 'before':
                                    sind = $(t).jqGrid('getGridRowById', src);
                                    if (sind) {
                                        $(sind).before(row.join(''));
                                        sind = sind.rowIndex - 1;
                                    }
                                    break;
                            }
                        }
                        if (t.p.subGrid === true) {
                            $(t).jqGrid("addSubGrid", gi + ni, sind);
                        }
                        //t.p.records++;
                        //t.p.reccount++;
                        //$(t).triggerHandler("jqGridAfterInsertRow", [rowid, data, data]);
                        //if (air) { t.p.afterInsertRow.call(t, rowid, data, data); }
                        k++;
                        if (t.p.datatype === 'local') {
                            //lcdata[t.p.localReader.id] = id;
                            //t.p._index[id] = t.p.data.length;
                            //t.p.data.push(lcdata);
                            lcdata = {};
                        }
                    }
                    if (t.p.altRows === true && !aradd) {
                        if (pos === "last") {
                            if ((t.rows.length - 1) % 2 === 1) { $(t.rows[t.rows.length - 1]).addClass(cn); }
                        } else {
                            $(t.rows).each(function (i) {
                                if (i % 2 === 1) { $(this).addClass(cn); }
                                else { $(this).removeClass(cn); }
                            });
                        }
                    }
                    //hdo
                    //t.updatepager(true, true);
                    success = true;

                    //add css class to further style the summary row
                    var jqRow = $("tr[role=row][id=" + rowid + "]");
                    jqRow.addClass("summary-row");

                    if (pos === 'after') {
                        jqRow.addClass("summary-row-after");
                    }

                    if (pos === 'before') {
                        jqRow.addClass("summary-row-before");
                    }

                    jqRow.find("td[role=summarygridcell]").addClass("summary-grid-cell");

                });
            }
            return success;
        },

        setInlineSummaryRowData: function (rowid, data, cssp) {
            var nm, success = true, title;
            this.each(function () {
                if (!this.grid) { return false; }
                var t = this, vl, ind, cp = typeof cssp, lcdata = {};
                ind = $(this).jqGrid('getGridRowById', rowid);
                if (!ind) { return false; }
                if (data) {
                    try {
                        $(this.p.colModel).each(function (i) {
                            nm = this.name;
                            var dval = $.jgrid.getAccessor(data, nm);
                            if (dval !== undefined) {
                                lcdata[nm] = this.formatter && typeof this.formatter === 'string' && this.formatter === 'date' ? $.unformat.date.call(t, dval, this) : dval;
                                vl = t.formatter(rowid, dval, i, data, 'edit');
                                if (this.isCheckbox) {
                                    vl = dval;
                                }
                                title = this.title ? { "title": $.jgrid.stripHtml(vl) } : {};
                                if (t.p.treeGrid === true && nm === t.p.ExpandColumn) {
                                    $("td[role='summarygridcell']:eq(" + i + ") > span:first", ind).html(vl).attr(title);
                                } else {
                                    $("td[role='summarygridcell']:eq(" + i + ")", ind).html(vl).attr(title);
                                    

                                }
                            }
                        });
                        if (t.p.datatype === 'local') {
                            var id = $.jgrid.stripPref(t.p.idPrefix, rowid),
                            pos = t.p._index[id], key;
                            if (t.p.treeGrid) {
                                for (key in t.p.treeReader) {
                                    if (t.p.treeReader.hasOwnProperty(key)) {
                                        delete lcdata[t.p.treeReader[key]];
                                    }
                                }
                            }
                            if (pos !== undefined) {
                                //hdo : do not change real data
                                //t.p.data[pos] = $.extend(true, t.p.data[pos], lcdata);
                            }
                            lcdata = null;
                        }
                    } catch (e) {
                        success = false;
                    }
                }
                if (success) {
                    //if (cp === 'string') { $(ind).addClass(cssp); } else if (cssp !== null && cp === 'object') { $(ind).css(cssp); }
                    //$(t).triggerHandler("jqGridAfterGridComplete");
                }
            });
            return success;
        },

        getSummaryRowData: function (rowid) {
            var res = {}, resall, getall = false, len, j = 0;
            this.each(function () {
                var $t = this, nm, ind;
                if (rowid === undefined) {
                    getall = true;
                    resall = [];
                    len = $t.rows.length;
                } else {
                    ind = $($t).jqGrid('getGridRowById', rowid);
                    if (!ind) { return res; }
                    len = 2;
                }
                while (j < len) {
                    if (getall) { ind = $t.rows[j]; }
                    if ($(ind).hasClass('summary-row')) {
                        $('td[role="summarygridcell"]', ind).each(function (i) {
                            nm = $t.p.colModel[i].name;
                            if (nm !== 'cb' && nm !== 'subgrid' && nm !== 'rn') {
                                if ($t.p.treeGrid === true && nm === $t.p.ExpandColumn) {
                                    res[nm] = $.jgrid.htmlDecode($("span:first", this).html());
                                } else {
                                    try {
                                        res[nm] = $.unformat.call($t, this, { rowId: ind.id, colModel: $t.p.colModel[i] }, i);
                                    } catch (e) {
                                        res[nm] = $.jgrid.htmlDecode($(this).html());
                                    }
                                }
                            }
                        });
                        if (getall) { resall.push(res); res = {}; }
                    }
                    j++;
                }
            });
            return resall || res;
        },

        getCol: function (col, obj, mathopr) {
            //modified to skip inline summary cells
            var ret = [], val, sum = 0, min, max, v;
            obj = typeof obj !== 'boolean' ? false : obj;
            if (mathopr === undefined) { mathopr = false; }
            this.each(function () {
                var $t = this, pos = -1;
                if (!$t.grid) { return; }
                if (isNaN(col)) {
                    $($t.p.colModel).each(function (i) {
                        if (this.name === col) {
                            pos = i; return false;
                        }
                    });
                } else { pos = parseInt(col, 10); }
                if (pos >= 0) {
                    var ln = $t.rows.length, i = 0, dlen = 0;
                    if (ln && ln > 0) {
                        while (i < ln) {
                            if ($($t.rows[i]).hasClass('jqgrow') && !$($t.rows[i]).hasClass('summary-row')) {
                                try {
                                    val = $.unformat.call($t, $($t.rows[i].cells[pos]), { rowId: $t.rows[i].id, colModel: $t.p.colModel[pos] }, pos);
                                } catch (e) {
                                    val = $.jgrid.htmlDecode($t.rows[i].cells[pos].innerHTML);
                                }
                                if (mathopr) {
                                    v = parseFloat(val);
                                    if (!isNaN(v)) {
                                        sum += v;
                                        if (max === undefined) { max = min = v; }
                                        min = Math.min(min, v);
                                        max = Math.max(max, v);
                                        dlen++;
                                    }
                                }
                                else if (obj) { ret.push({ id: $t.rows[i].id, value: val }); }
                                else { ret.push(val); }
                            }
                            i++;
                        }
                        if (mathopr) {
                            switch (mathopr.toLowerCase()) {
                                case 'sum': ret = sum; break;
                                case 'avg': ret = sum / dlen; break;
                                case 'count': ret = (ln - 1); break;
                                case 'min': ret = min; break;
                                case 'max': ret = max; break;
                            }
                        }
                    }
                }
            });
            return ret;
        },

        getFilteredCol: function (col, obj, mathopr,isFiltered) {
            //modified to take only rows that are filtered by the callback function isFiltered()
            var ret = [], val, sum = 0, min, max, v;
            obj = typeof obj !== 'boolean' ? false : obj;
            if (mathopr === undefined) { mathopr = false; }
            this.each(function () {
                var $t = this, pos = -1;
                if (!$t.grid) { return; }
                if (isNaN(col)) {
                    $($t.p.colModel).each(function (i) {
                        if (this.name === col) {
                            pos = i; return false;
                        }
                    });
                } else { pos = parseInt(col, 10); }
                if (pos >= 0) {
                    var ln = $t.rows.length, i = 0, dlen = 0;
                    if (ln && ln > 0) {
                        while (i < ln) {
                            //hdo
                            //if ($($t.rows[i]).hasClass('jqgrow') && !$($t.rows[i]).hasClass('summary-row')) {
                            if (isFiltered($t.rows[i])) {
                                try {
                                    val = $.unformat.call($t, $($t.rows[i].cells[pos]), { rowId: $t.rows[i].id, colModel: $t.p.colModel[pos] }, pos);
                                } catch (e) {
                                    val = $.jgrid.htmlDecode($t.rows[i].cells[pos].innerHTML);
                                }
                                if (mathopr) {
                                    v = parseFloat(val);
                                    if (!isNaN(v)) {
                                        sum += v;
                                        if (max === undefined) { max = min = v; }
                                        min = Math.min(min, v);
                                        max = Math.max(max, v);
                                        dlen++;
                                    }
                                }
                                else if (obj) { ret.push({ id: $t.rows[i].id, value: val }); }
                                else { ret.push(val); }
                            }
                            i++;
                        }
                        if (mathopr) {
                            switch (mathopr.toLowerCase()) {
                                case 'sum': ret = sum; break;
                                case 'avg': ret = sum / dlen; break;
                                case 'count': ret = (ln - 1); break;
                                case 'min': ret = min; break;
                                case 'max': ret = max; break;
                            }
                        }
                    }
                }
            });
            return ret;
        },

        getFilteredColAsync: function (col, obj, mathopr,isFiltered, onEnd) {
            //modified to take only rows that are filtered by the callback function isFiltered()
            //modified also to process each row in asynchronously.
            // warning : this method has a dependency on vpGrid library
            var ret = [], val, sum = 0, min, max, v;
            obj = typeof obj !== 'boolean' ? false : obj;
            if (mathopr === undefined) { mathopr = false; }
            this.each(function () {
                var $t = this, pos = -1;
                if (!$t.grid) { return; }
                if (isNaN(col)) {
                    $($t.p.colModel).each(function (i) {
                        if (this.name === col) {
                            pos = i; return false;
                        }
                    });
                } else { pos = parseInt(col, 10); }
                if (pos >= 0) {
                    var ln = $t.rows.length, i = 0, dlen = 0;

                    if (ln && ln > 0) {

                        //hdo : create a true javascript array of grid rows
                        var rowsArray = $.makeArray($t.rows);

                        vpGrid.executeAsyncLoopOnArray(rowsArray,
                            function (i, item) {
                                var row = item;
                                //hdo
                                //if ($($t.rows[i]).hasClass('jqgrow') && !$($t.rows[i]).hasClass('summary-row')) {
                                if (isFiltered(row)) {
                                    try {
                                        val = $.unformat.call($t, $(row.cells[pos]), { rowId: row.id, colModel: $t.p.colModel[pos] }, pos);
                                    } catch (e) {
                                        val = $.jgrid.htmlDecode(row.cells[pos].innerHTML);
                                    }
                                    if (mathopr) {
                                        v = parseFloat(val);
                                        if (!isNaN(v)) {
                                            sum += v;
                                            if (max === undefined) { max = min = v; }
                                            min = Math.min(min, v);
                                            max = Math.max(max, v);
                                            dlen++;
                                        }
                                    }
                                    else if (obj) { ret.push({ id: row.id, value: val }); }
                                    else { ret.push(val); }
                                }


                            }, // end callback
                            this, // context
                            function () { // onEnd callback
                                try {
                                    if (mathopr) {
                                        switch (mathopr.toLowerCase()) {
                                            case 'sum': ret = sum; break;
                                            case 'avg': ret = sum / dlen; break;
                                            case 'count': ret = (ln - 1); break;
                                            case 'min': ret = min; break;
                                            case 'max': ret = max; break;
                                        }
                                    }
                                    onEnd.call(this, ret);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            } //end onEnd callback
                            ); // end vpGrid.executeAsyncLoopOnArray

                        
                    }
                }
            });
            return ret;
        },

        //TODO : urgent refactor $t.p.savedRow mangement in clientArray mode 
        //        --> $t.p.savedRow has a design problem when working in inline cell editing mode


        editCell: function (iRow, iCol, ed) {
            //modified to change the management of $t.p.savedRow in clientArray mode
            return this.each(function () {
                var $t = this, nm, tmp, cc, cm;
                if (!$t.grid || $t.p.cellEdit !== true) { return; }
                iCol = parseInt(iCol, 10);
                // select the row that can be used for other methods
                $t.p.selrow = $t.rows[iRow].id;
                if (!$t.p.knv) { $($t).jqGrid("GridNav"); }
                // check to see if we have already edited cell
                if ($t.p.savedRow.length > 0) {
                    // prevent second click on that field and enable selects
                    if (ed === true) {
                        if (iRow == $t.p.iRow && iCol == $t.p.iCol) {
                            //hdo : prevent exiting from edit mode
                            //return;
                            $t.p.savedRow = [];
                        }
                        else { //hdo : added else
                            $($t).jqGrid("saveCell", $t.p.savedRow[0].id, $t.p.savedRow[0].ic);
                        }
                    }
                    // save the cell
                    // hdo : moved aboved
                    //$($t).jqGrid("saveCell", $t.p.savedRow[0].id, $t.p.savedRow[0].ic);
                } else {
                    window.setTimeout(function () { $("#" + $.jgrid.jqID($t.p.knv)).attr("tabindex", "-1").focus(); }, 0);
                }
                cm = $t.p.colModel[iCol];
                nm = cm.name;
                if (nm === 'subgrid' || nm === 'cb' || nm === 'rn') { return; }
                cc = $("td:eq(" + iCol + ")", $t.rows[iRow]);
                if (cm.editable === true && ed === true && !cc.hasClass("not-editable-cell")) {
                    if (parseInt($t.p.iCol, 10) >= 0 && parseInt($t.p.iRow, 10) >= 0) {
                        $("td:eq(" + $t.p.iCol + ")", $t.rows[$t.p.iRow]).removeClass("edit-cell ui-state-highlight");
                        $($t.rows[$t.p.iRow]).removeClass("selected-row ui-state-hover");
                    }
                    $(cc).addClass("edit-cell ui-state-highlight");
                    $($t.rows[iRow]).addClass("selected-row ui-state-hover");
                    try {
                        tmp = $.unformat.call($t, cc, { rowId: $t.rows[iRow].id, colModel: cm }, iCol);
                    } catch (_) {
                        tmp = (cm.edittype && cm.edittype === 'textarea') ? $(cc).text() : $(cc).html();
                    }
                    if ($t.p.autoencode) { tmp = $.jgrid.htmlDecode(tmp); }
                    if (!cm.edittype) { cm.edittype = "text"; }
                    $t.p.savedRow.push({ id: iRow, ic: iCol, name: nm, v: tmp });
                    if (tmp === "&nbsp;" || tmp === "&#160;" || (tmp.length === 1 && tmp.charCodeAt(0) === 160)) { tmp = ''; }
                    if ($.isFunction($t.p.formatCell)) {
                        var tmp2 = $t.p.formatCell.call($t, $t.rows[iRow].id, nm, tmp, iRow, iCol);
                        if (tmp2 !== undefined) { tmp = tmp2; }
                    }
                    $($t).triggerHandler("jqGridBeforeEditCell", [$t.rows[iRow].id, nm, tmp, iRow, iCol]);
                    if ($.isFunction($t.p.beforeEditCell)) {
                        $t.p.beforeEditCell.call($t, $t.rows[iRow].id, nm, tmp, iRow, iCol);
                    }
                    var opt = $.extend({}, cm.editoptions || {}, { id: iRow + "_" + nm, name: nm });
                    var elc = $.jgrid.createEl.call($t, cm.edittype, opt, tmp, true, $.extend({}, $.jgrid.ajaxOptions, $t.p.ajaxSelectOptions || {}));
                    $(cc).html("").append(elc).attr("tabindex", "0");
                    $.jgrid.bindEv.call($t, elc, opt);
                    window.setTimeout(function () { $(elc).focus(); }, 0);
                    $("input, select, textarea", cc).bind("keydown", function (e) {
                        if (e.keyCode === 27) {
                            if ($("input.hasDatepicker", cc).length > 0) {
                                if ($(".ui-datepicker").is(":hidden")) { $($t).jqGrid("restoreCell", iRow, iCol); }
                                else { $("input.hasDatepicker", cc).datepicker('hide'); }
                            } else {
                                $($t).jqGrid("restoreCell", iRow, iCol);
                            }
                        } //ESC
                        if (e.keyCode === 13) {
                            $($t).jqGrid("saveCell", iRow, iCol);
                            // Prevent default action
                            return false;
                        } //Enter
                        if (e.keyCode === 9) {
                            if (!$t.grid.hDiv.loading) {
                                if (e.shiftKey) { $($t).jqGrid("prevCell", iRow, iCol); } //Shift TAb
                                else { $($t).jqGrid("nextCell", iRow, iCol); } //Tab
                            } else {
                                return false;
                            }
                        }
                        e.stopPropagation();
                    });
                    $($t).triggerHandler("jqGridAfterEditCell", [$t.rows[iRow].id, nm, tmp, iRow, iCol]);
                    if ($.isFunction($t.p.afterEditCell)) {
                        $t.p.afterEditCell.call($t, $t.rows[iRow].id, nm, tmp, iRow, iCol);
                    }
                } else {
                    if (parseInt($t.p.iCol, 10) >= 0 && parseInt($t.p.iRow, 10) >= 0) {
                        $("td:eq(" + $t.p.iCol + ")", $t.rows[$t.p.iRow]).removeClass("edit-cell ui-state-highlight");
                        $($t.rows[$t.p.iRow]).removeClass("selected-row ui-state-hover");
                    }
                    cc.addClass("edit-cell ui-state-highlight");
                    $($t.rows[iRow]).addClass("selected-row ui-state-hover");
                    tmp = cc.html().replace(/\&#160\;/ig, '');
                    $($t).triggerHandler("jqGridSelectCell", [$t.rows[iRow].id, nm, tmp, iRow, iCol]);
                    if ($.isFunction($t.p.onSelectCell)) {
                        $t.p.onSelectCell.call($t, $t.rows[iRow].id, nm, tmp, iRow, iCol);
                    }
                }
                $t.p.iCol = iCol; $t.p.iRow = iRow;
            });
        },

        saveCell: function (iRow, iCol) {
            //modified to change call of the error modal dialog box
            //modified to change the management of $t.p.savedRow in clientArray mode
            return this.each(function () {
                var $t = this, fr;
                if (!$t.grid || $t.p.cellEdit !== true) { return; }
                if ($t.p.savedRow.length >= 1) { fr = 0; } else { fr = null; }
                if (fr !== null) {
                    var cc = $("td:eq(" + iCol + ")", $t.rows[iRow]), v, v2,
                    cm = $t.p.colModel[iCol], nm = cm.name, nmjq = $.jgrid.jqID(nm);
                    switch (cm.edittype) {
                        case "select":
                            if (!cm.editoptions.multiple) {
                                v = $("#" + iRow + "_" + nmjq + " option:selected", $t.rows[iRow]).val();
                                v2 = $("#" + iRow + "_" + nmjq + " option:selected", $t.rows[iRow]).text();
                            } else {
                                var sel = $("#" + iRow + "_" + nmjq, $t.rows[iRow]), selectedText = [];
                                v = $(sel).val();
                                if (v) { v.join(","); } else { v = ""; }
                                $("option:selected", sel).each(
                                    function (i, selected) {
                                        selectedText[i] = $(selected).text();
                                    }
                                );
                                v2 = selectedText.join(",");
                            }
                            if (cm.formatter) { v2 = v; }
                            break;
                        case "checkbox":
                            var cbv = ["Yes", "No"];
                            if (cm.editoptions) {
                                cbv = cm.editoptions.value.split(":");
                            }
                            v = $("#" + iRow + "_" + nmjq, $t.rows[iRow]).is(":checked") ? cbv[0] : cbv[1];
                            v2 = v;
                            break;
                        case "password":
                        case "text":
                        case "textarea":
                        case "button":
                            v = $("#" + iRow + "_" + nmjq, $t.rows[iRow]).val();
                            v2 = v;
                            break;
                        case 'custom':
                            try {
                                if (cm.editoptions && $.isFunction(cm.editoptions.custom_value)) {
                                    v = cm.editoptions.custom_value.call($t, $(".customelement", cc), 'get');
                                    if (v === undefined) { throw "e2"; } else { v2 = v; }
                                } else { throw "e1"; }
                            } catch (e) {
                                if (e === "e1") { $.jgrid.info_dialog($.jgrid.errors.errcap, "function 'custom_value' " + $.jgrid.edit.msg.nodefined, $.jgrid.edit.bClose); }
                                if (e === "e2") { $.jgrid.info_dialog($.jgrid.errors.errcap, "function 'custom_value' " + $.jgrid.edit.msg.novalue, $.jgrid.edit.bClose); }
                                else { $.jgrid.info_dialog($.jgrid.errors.errcap, e.message, $.jgrid.edit.bClose); }
                            }
                            break;
                    }

                    //hdo : check input value
                    if (v === undefined || v === null) {
                        $t.p.savedRow.splice(0, 1);
                        $($t).jqGrid("restoreCell", iRow, iCol);
                        window.setTimeout(function () { $("#" + $.jgrid.jqID($t.p.knv)).attr("tabindex", "-1").focus(); }, 0);
                        return;
                    }

                    // The common approach is if nothing changed do not do anything
                    if (v2 !== $t.p.savedRow[fr].v) {
                        var vvv = $($t).triggerHandler("jqGridBeforeSaveCell", [$t.rows[iRow].id, nm, v, iRow, iCol]);
                        if (vvv) { v = vvv; v2 = vvv; }
                        if ($.isFunction($t.p.beforeSaveCell)) {
                            var vv = $t.p.beforeSaveCell.call($t, $t.rows[iRow].id, nm, v, iRow, iCol);
                            if (vv) { v = vv; v2 = vv; }
                        }
                        var cv = $.jgrid.checkValues.call($t, v, iCol);
                        if (cv[0] === true) {
                            var addpost = $($t).triggerHandler("jqGridBeforeSubmitCell", [$t.rows[iRow].id, nm, v, iRow, iCol]) || {};
                            if ($.isFunction($t.p.beforeSubmitCell)) {
                                addpost = $t.p.beforeSubmitCell.call($t, $t.rows[iRow].id, nm, v, iRow, iCol);
                                if (!addpost) { addpost = {}; }
                            }
                            if ($("input.hasDatepicker", cc).length > 0) { $("input.hasDatepicker", cc).datepicker('hide'); }
                            if ($t.p.cellsubmit === 'remote') {
                                if ($t.p.cellurl) {
                                    var postdata = {};
                                    if ($t.p.autoencode) { v = $.jgrid.htmlEncode(v); }
                                    postdata[nm] = v;
                                    var idname, oper, opers;
                                    opers = $t.p.prmNames;
                                    idname = opers.id;
                                    oper = opers.oper;
                                    postdata[idname] = $.jgrid.stripPref($t.p.idPrefix, $t.rows[iRow].id);
                                    postdata[oper] = opers.editoper;
                                    postdata = $.extend(addpost, postdata);
                                    $("#lui_" + $.jgrid.jqID($t.p.id)).show();
                                    $t.grid.hDiv.loading = true;
                                    $.ajax($.extend({
                                        url: $t.p.cellurl,
                                        data: $.isFunction($t.p.serializeCellData) ? $t.p.serializeCellData.call($t, postdata) : postdata,
                                        type: "POST",
                                        complete: function (result, stat) {
                                            $("#lui_" + $t.p.id).hide();
                                            $t.grid.hDiv.loading = false;
                                            if (stat === 'success') {
                                                var ret = $($t).triggerHandler("jqGridAfterSubmitCell", [$t, result, postdata.id, nm, v, iRow, iCol]) || [true, ''];
                                                if (ret[0] === true && $.isFunction($t.p.afterSubmitCell)) {
                                                    ret = $t.p.afterSubmitCell.call($t, result, postdata.id, nm, v, iRow, iCol);
                                                }
                                                if (ret[0] === true) {
                                                    $(cc).empty();
                                                    $($t).jqGrid("setCell", $t.rows[iRow].id, iCol, v2, false, false, true);
                                                    $(cc).addClass("dirty-cell");
                                                    $($t.rows[iRow]).addClass("edited");
                                                    $($t).triggerHandler("jqGridAfterSaveCell", [$t.rows[iRow].id, nm, v, iRow, iCol]);
                                                    if ($.isFunction($t.p.afterSaveCell)) {
                                                        $t.p.afterSaveCell.call($t, $t.rows[iRow].id, nm, v, iRow, iCol);
                                                    }
                                                    $t.p.savedRow.splice(0, 1);
                                                } else {
                                                    $.jgrid.info_dialog($.jgrid.errors.errcap, ret[1], $.jgrid.edit.bClose);
                                                    $($t).jqGrid("restoreCell", iRow, iCol);
                                                }
                                            }
                                        },
                                        error: function (res, stat, err) {
                                            $("#lui_" + $.jgrid.jqID($t.p.id)).hide();
                                            $t.grid.hDiv.loading = false;
                                            $($t).triggerHandler("jqGridErrorCell", [res, stat, err]);
                                            if ($.isFunction($t.p.errorCell)) {
                                                $t.p.errorCell.call($t, res, stat, err);
                                                $($t).jqGrid("restoreCell", iRow, iCol);
                                            } else {
                                                $.jgrid.info_dialog($.jgrid.errors.errcap, res.status + " : " + res.statusText + "<br/>" + stat, $.jgrid.edit.bClose);
                                                $($t).jqGrid("restoreCell", iRow, iCol);
                                            }
                                        }
                                    }, $.jgrid.ajaxOptions, $t.p.ajaxCellOptions || {}));
                                } else {
                                    try {
                                        $.jgrid.info_dialog($.jgrid.errors.errcap, $.jgrid.errors.nourl, $.jgrid.edit.bClose);
                                        $($t).jqGrid("restoreCell", iRow, iCol);
                                    } catch (e) { }
                                }
                            }
                            if ($t.p.cellsubmit === 'clientArray') {
                                // hdo : release early the buffer that saves the original cell value while in editing mode
                                $t.p.savedRow.splice(0, 1);

                                $(cc).empty();
                                $($t).jqGrid("setCell", $t.rows[iRow].id, iCol, v2, false, false, true);
                                $(cc).addClass("dirty-cell");
                                $($t.rows[iRow]).addClass("edited");
                                $($t).triggerHandler("jqGridAfterSaveCell", [$t.rows[iRow].id, nm, v, iRow, iCol]);
                                if ($.isFunction($t.p.afterSaveCell)) {
                                    $t.p.afterSaveCell.call($t, $t.rows[iRow].id, nm, v, iRow, iCol);
                                }
                                //hdo : moved at the top of the if, because aftersavecell executes heavy asynchronous process preventing other cells to be changed in the meantime
                                //$t.p.savedRow.splice(0, 1);
                            }
                        } else {
                            try {
                                //hdo
                                //window.setTimeout(function () { $.jgrid.info_dialog($.jgrid.errors.errcap, v + " " + cv[1], $.jgrid.edit.bClose); }, 100);
                                window.setTimeout(function () { $.jgrid.info_dialog($.jgrid.errors.errcap, cv[1], $.jgrid.edit.bClose); }, 100);

                                $($t).jqGrid("restoreCell", iRow, iCol);
                            } catch (e) { }
                        }
                    } else {
                        $($t).jqGrid("restoreCell", iRow, iCol);
                    }
                }
                window.setTimeout(function () { $("#" + $.jgrid.jqID($t.p.knv)).attr("tabindex", "-1").focus(); }, 0);
            });
        },

        footerData2: function (action, data, format,uiIdentifier) {
            var nm, success = false, res = {}, title;
            function isEmpty(obj) {
                var i;
                for (i in obj) {
                    if (obj.hasOwnProperty(i)) { return false; }
                }
                return true;
            }
            if (action == undefined) { action = "get"; }
            if (typeof format !== "boolean") { format = true; }
            action = action.toLowerCase();
            this.each(function () {
                var t = this, vl;
                if (!t.grid || !t.p.footerrow) { return false; }
                if (action === "set") { if (isEmpty(data)) { return false; } }
                success = true;
                $(this.p.colModel).each(function (i) {
                    nm = this.name;
                    if (action === "set") {
                        if (data[nm] !== undefined) {
                            vl = format ? t.formatter("", data[nm], i, data, 'edit') : data[nm];
                            title = this.title ? { "title": $.jgrid.stripHtml(vl) } : {};
                            $("tr[data-vpgrid-ui-id=" + uiIdentifier + "].footrow td:eq(" + i + ")", t.grid.sDiv).html(vl).attr(title);
                            success = true;
                        }
                    } else if (action === "get") {
                        res[nm] = $("tr[data-vpgrid-ui-id=" + uiIdentifier + "].footrow td:eq(" + i + ")", t.grid.sDiv).html();
                    }
                });
            });
            return action === "get" ? res : success;
        },

        //hdo : modified to disable the first checkbox until event handler is bound to it
        //hdo : modified to add the data-vpgrid-column-name attribute on grid cells
        addRowData: function (rowid, rdata, pos, src) {
            if (!pos) { pos = "last"; }
            var success = false, nm, row, gi, si, ni, sind, i, v, prp = "", aradd, cnm, cn, data, cm, id;
            if (rdata) {
                if ($.isArray(rdata)) {
                    aradd = true;
                    pos = "last";
                    cnm = rowid;
                } else {
                    rdata = [rdata];
                    aradd = false;
                }

                this.formatCol = function (pos, rowInd, tv, rawObject, rowId, rdata) {
                    var cm = ts.p.colModel[pos],
                    ral = cm.align, result = "style=\"", clas = cm.classes, nm = cm.name, celp, acp = [];
                    if (ral) { result += "text-align:" + ral + ";"; }
                    if (cm.hidden === true) { result += "display:none;"; }
                    if (rowInd === 0) {
                        result += "width: " + grid.headers[pos].width + "px;";
                    } else if (cm.cellattr && $.isFunction(cm.cellattr)) {
                        celp = cm.cellattr.call(ts, rowId, tv, rawObject, cm, rdata);
                        if (celp && typeof celp === "string") {
                            celp = celp.replace(/style/i, 'style').replace(/title/i, 'title');
                            if (celp.indexOf('title') > -1) { cm.title = false; }
                            if (celp.indexOf('class') > -1) { clas = undefined; }
                            acp = celp.replace('-style', '-sti').split(/style/);
                            if (acp.length === 2) {
                                acp[1] = $.trim(acp[1].replace('-sti', '-style').replace("=", ""));
                                if (acp[1].indexOf("'") === 0 || acp[1].indexOf('"') === 0) {
                                    acp[1] = acp[1].substring(1);
                                }
                                result += acp[1].replace(/'/gi, '"');
                            } else {
                                result += "\"";
                            }
                        }
                    }
                    if (!acp.length) { acp[0] = ""; result += "\""; }
                    result += (clas !== undefined ? (" class=\"" + clas + "\"") : "") + ((cm.title && tv) ? (" title=\"" + $.jgrid.stripHtml(tv) + "\"") : "");
                    result += " aria-describedby=\"" + ts.p.id + "_" + nm + "\"";
                    result += " data-vpgrid-column-name=\"" + nm + "\"";
                    return result + acp[0];
                }; // end formatCol

                this.each(function () {
                    var t = this, datalen = rdata.length;
                    ni = t.p.rownumbers === true ? 1 : 0;
                    gi = t.p.multiselect === true ? 1 : 0;
                    si = t.p.subGrid === true ? 1 : 0;
                    if (!aradd) {
                        if (rowid !== undefined) { rowid = String(rowid); }
                        else {
                            rowid = $.jgrid.randId();
                            if (t.p.keyIndex !== false) {
                                cnm = t.p.colModel[t.p.keyIndex + gi + si + ni].name;
                                if (rdata[0][cnm] !== undefined) { rowid = rdata[0][cnm]; }
                            }
                        }
                    }
                    cn = t.p.altclass;
                    var k = 0, cna = "", lcdata = {},
                    air = $.isFunction(t.p.afterInsertRow) ? true : false;
                    while (k < datalen) {
                        data = rdata[k];
                        row = [];
                        if (aradd) {
                            try {
                                rowid = data[cnm];
                                if (rowid === undefined) {
                                    rowid = $.jgrid.randId();
                                }
                            }
                            catch (e) { rowid = $.jgrid.randId(); }
                            cna = t.p.altRows === true ? (t.rows.length - 1) % 2 === 0 ? cn : "" : "";
                        }
                        id = rowid;
                        rowid = t.p.idPrefix + rowid;
                        if (ni) {
                            prp = t.formatCol(0, 1, '', null, rowid, true);
                            row[row.length] = "<td role=\"gridcell\" class=\"ui-state-default jqgrid-rownum\" " + prp + ">0</td>";
                        }
                        if (gi) {
                            //hdo : add disabled attribute to the checkbox
                            //v = "<input role=\"checkbox\" type=\"checkbox\""+" id=\"jqg_"+t.p.id+"_"+rowid+"\" class=\"cbox\"/>";
                            v = "<input disabled=\"disabled\" role=\"checkbox\" type=\"checkbox\"" + " id=\"jqg_" + t.p.id + "_" + rowid + "\" class=\"cbox\"/>";

                            prp = t.formatCol(ni, 1, '', null, rowid, true);

                            //hdo : inject  data-vpgrid-column-name attribute
                            var prp2 = ' data-vpgrid-column-name="cb"';

                            //row[row.length] = "<td role=\"gridcell\" " + prp + ">" + v + "</td>";
                            row[row.length] = "<td role=\"gridcell\" " + prp + prp2 + ">" + v + "</td>";
                        }
                        if (si) {
                            row[row.length] = $(t).jqGrid("addSubGridCell", gi + ni, 1);
                        }
                        for (i = gi + si + ni; i < t.p.colModel.length; i++) {
                            cm = t.p.colModel[i];
                            nm = cm.name;
                            lcdata[nm] = data[nm];
                            v = t.formatter(rowid, $.jgrid.getAccessor(data, nm), i, data);
                            prp = t.formatCol(i, 1, v, data, rowid, lcdata);
                            //hdo : inject  data-vpgrid-column-name attribute
                            var prp2 = ' data-vpgrid-column-name="' + nm + '"';

                            //row[row.length] = "<td role=\"gridcell\" " + prp + ">" + v + "</td>";
                            row[row.length] = "<td role=\"gridcell\" " + prp + prp2 + ">" + v + "</td>";

                        }
                        row.unshift(t.constructTr(rowid, false, cna, lcdata, data, false));
                        row[row.length] = "</tr>";
                        if (t.rows.length === 0) {
                            $("table:first", t.grid.bDiv).append(row.join(''));
                        } else {
                            switch (pos) {
                                case 'last':
                                    $(t.rows[t.rows.length - 1]).after(row.join(''));
                                    sind = t.rows.length - 1;
                                    break;
                                case 'first':
                                    $(t.rows[0]).after(row.join(''));
                                    sind = 1;
                                    break;
                                case 'after':
                                    sind = $(t).jqGrid('getGridRowById', src);
                                    if (sind) {
                                        if ($(t.rows[sind.rowIndex + 1]).hasClass("ui-subgrid")) { $(t.rows[sind.rowIndex + 1]).after(row); }
                                        else { $(sind).after(row.join('')); }
                                        sind = sind.rowIndex + 1;
                                    }
                                    break;
                                case 'before':
                                    sind = $(t).jqGrid('getGridRowById', src);
                                    if (sind) {
                                        $(sind).before(row.join(''));
                                        sind = sind.rowIndex - 1;
                                    }
                                    break;
                            }
                        }
                        if (t.p.subGrid === true) {
                            $(t).jqGrid("addSubGrid", gi + ni, sind);
                        }
                        t.p.records++;
                        t.p.reccount++;
                        $(t).triggerHandler("jqGridAfterInsertRow", [rowid, data, data]);
                        if (air) { t.p.afterInsertRow.call(t, rowid, data, data); }
                        k++;
                        if (t.p.datatype === 'local') {
                            lcdata[t.p.localReader.id] = id;
                            t.p._index[id] = t.p.data.length;
                            t.p.data.push(lcdata);
                            lcdata = {};
                        }
                    }
                    if (t.p.altRows === true && !aradd) {
                        if (pos === "last") {
                            if ((t.rows.length - 1) % 2 === 1) { $(t.rows[t.rows.length - 1]).addClass(cn); }
                        } else {
                            $(t.rows).each(function (i) {
                                if (i % 2 === 1) { $(this).addClass(cn); }
                                else { $(this).removeClass(cn); }
                            });
                        }
                    }
                    t.updatepager(true, true);
                    success = true;
                });
            }
            return success;
        },

        //hdo : created to add asynchronously every row in the grid from a data array
        //warning : has a dependency on vpGrid
        addRowDataArray : function(startIndex,rdata,onProgress, onEnd, cancel, onCanceled) {
            var src = undefined;
            var pos = "last"
            var success = false, nm, row, gi, si, ni,sind, i, v, prp="", aradd, cnm, cn, data, cm, id;
            if(rdata) {
                aradd = true;

                this.formatCol = function (pos, rowInd, tv, rawObject, rowId, rdata) {
                    var cm = ts.p.colModel[pos],
                    ral = cm.align, result = "style=\"", clas = cm.classes, nm = cm.name, celp, acp = [];
                    if (ral) { result += "text-align:" + ral + ";"; }
                    if (cm.hidden === true) { result += "display:none;"; }
                    if (rowInd === 0) {
                        result += "width: " + grid.headers[pos].width + "px;";
                    } else if (cm.cellattr && $.isFunction(cm.cellattr)) {
                        celp = cm.cellattr.call(ts, rowId, tv, rawObject, cm, rdata);
                        if (celp && typeof celp === "string") {
                            celp = celp.replace(/style/i, 'style').replace(/title/i, 'title');
                            if (celp.indexOf('title') > -1) { cm.title = false; }
                            if (celp.indexOf('class') > -1) { clas = undefined; }
                            acp = celp.replace('-style', '-sti').split(/style/);
                            if (acp.length === 2) {
                                acp[1] = $.trim(acp[1].replace('-sti', '-style').replace("=", ""));
                                if (acp[1].indexOf("'") === 0 || acp[1].indexOf('"') === 0) {
                                    acp[1] = acp[1].substring(1);
                                }
                                result += acp[1].replace(/'/gi, '"');
                            } else {
                                result += "\"";
                            }
                        }
                    }
                    if (!acp.length) { acp[0] = ""; result += "\""; }
                    result += (clas !== undefined ? (" class=\"" + clas + "\"") : "") + ((cm.title && tv) ? (" title=\"" + $.jgrid.stripHtml(tv) + "\"") : "");
                    result += " aria-describedby=\"" + ts.p.id + "_" + nm + "\"";
                    result += " data-vpgrid-column-name=\"" + nm + "\"";
                    return result + acp[0];
                }; // end formatCol

                this.each(function() {
                    var t = this, datalen = rdata.length;
                    ni = t.p.rownumbers===true ? 1 :0;
                    gi = t.p.multiselect ===true ? 1 :0;
                    si = t.p.subGrid===true ? 1 :0;
                    
                    cn = t.p.altclass;
                    var k = 0, cna ="", lcdata = {},
                    air = $.isFunction(t.p.afterInsertRow) ? true : false;
                
                    vpGrid.executeAsyncLoopOnArray(rdata,
                        function (k, data) {
                            try {
                                row = [];
                                var rowIndex = startIndex + k;
                                var rowid = t.p.idPrefix + rowIndex;
                                cna = t.p.altRows === true ? (t.rows.length - 1) % 2 === 0 ? cn : "" : "";
                                id = rowid;
  
                                if (ni) {
                                    prp = t.formatCol(0, 1, '', null, rowid, true);
                                    row[row.length] = "<td role=\"gridcell\" class=\"ui-state-default jqgrid-rownum\" " + prp + ">0</td>";
                                }
                                if (gi) {
                                    //hdo : add disabled attribute to the checkbox
                                    //v = "<input role=\"checkbox\" type=\"checkbox\""+" id=\"jqg_"+t.p.id+"_"+rowid+"\" class=\"cbox\"/>";
                                    v = "<input disabled=\"disabled\" role=\"checkbox\" type=\"checkbox\"" + " id=\"jqg_" + t.p.id + "_" + rowid + "\" class=\"cbox\"/>";

                                    prp = t.formatCol(ni, 1, '', null, rowid, true);

                                    //hdo : inject  data-vpgrid-column-name attribute
                                    var prp2 = ' data-vpgrid-column-name="cb"';

                                    //row[row.length] = "<td role=\"gridcell\" " + prp + ">" + v + "</td>";
                                    row[row.length] = "<td role=\"gridcell\" " + prp + prp2 + ">" + v + "</td>";
                                }
                                if (si) {
                                    row[row.length] = $(t).jqGrid("addSubGridCell", gi + ni, 1);
                                }
                                for (i = gi + si + ni; i < t.p.colModel.length; i++) {
                                    cm = t.p.colModel[i];
                                    nm = cm.name;
                                    lcdata[nm] = data[nm];
                                    v = t.formatter(rowid, $.jgrid.getAccessor(data, nm), i, data);
                                    prp = t.formatCol(i, 1, v, data, rowid, lcdata);
                                    //hdo : inject  data-vpgrid-column-name attribute
                                    var prp2 = ' data-vpgrid-column-name="' + nm + '"';

                                    //row[row.length] = "<td role=\"gridcell\" " + prp + ">" + v + "</td>";
                                    row[row.length] = "<td role=\"gridcell\" " + prp + prp2 + ">" + v + "</td>";

                                }
                                row.unshift(t.constructTr(rowid, false, cna, lcdata, data, false));
                                row[row.length] = "</tr>";
                                if (t.rows.length === 0) {
                                    $("table:first", t.grid.bDiv).append(row.join(''));
                                } else {
                                    switch (pos) {
                                        case 'last':
                                            $(t.rows[t.rows.length - 1]).after(row.join(''));
                                            sind = t.rows.length - 1;
                                            break;
                                        case 'first':
                                            $(t.rows[0]).after(row.join(''));
                                            sind = 1;
                                            break;
                                        case 'after':
                                            sind = $(t).jqGrid('getGridRowById', src);
                                            if (sind) {
                                                if ($(t.rows[sind.rowIndex + 1]).hasClass("ui-subgrid")) { $(t.rows[sind.rowIndex + 1]).after(row); }
                                                else { $(sind).after(row.join('')); }
                                                sind = sind.rowIndex + 1;
                                            }
                                            break;
                                        case 'before':
                                            sind = $(t).jqGrid('getGridRowById', src);
                                            if (sind) {
                                                $(sind).before(row.join(''));
                                                sind = sind.rowIndex - 1;
                                            }
                                            break;
                                    }
                                }
                                if (t.p.subGrid === true) {
                                    $(t).jqGrid("addSubGrid", gi + ni, sind);
                                }
                                t.p.records++;
                                t.p.reccount++;
                                $(t).triggerHandler("jqGridAfterInsertRow", [rowid, data, data]);
                                if (air) { t.p.afterInsertRow.call(t, rowid, data, data); }
                            
                                if (t.p.datatype === 'local') {
                                    lcdata[t.p.localReader.id] = id;
                                    t.p._index[id] = t.p.data.length;
                                    t.p.data.push(lcdata);
                                    lcdata = {};
                                }
                            
                                if (onProgress) {
                                    onProgress.call(t, k);
                                }
                                    
                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        }, // end callback that process item k/data
                        t, // context
                        function () { // onEnd callback
                            try {
                                if (t.p.altRows === true && !aradd) {
                                    if (pos === "last") {
                                        if ((t.rows.length - 1) % 2 === 1) { $(t.rows[t.rows.length - 1]).addClass(cn); }
                                    } else {
                                        $(t.rows).each(function (i) {
                                            if (i % 2 === 1) { $(this).addClass(cn); }
                                            else { $(this).removeClass(cn); }
                                        });
                                    }
                                }
                                t.updatepager(true, true);
                                if (onEnd) {
                                    onEnd.call(t);
                                }
                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        },
                        cancel,onCanceled
                        );

                    success = true;
                });
            }
            return success;
        },







        //hdo : created to add asynchronously every row in the grid from a data array
        //warning : has a dependency on vpGrid
        addRowDataArrayWithNoRowInsertionInDOM : function(startIndex,rdata,onProgress, onEnd, cancel, onCanceled) {
            var src = undefined;
            var pos = "last"
            var success = false, nm, row, gi, si, ni,sind, i, v, prp="", aradd, cnm, cn, data, cm, id;
            if(rdata) {
                aradd = true;

                this.formatCol = function (pos, rowInd, tv, rawObject, rowId, rdata) {
                    var cm = ts.p.colModel[pos],
                    ral = cm.align, result = "style=\"", clas = cm.classes, nm = cm.name, celp, acp = [];
                    if (ral) { result += "text-align:" + ral + ";"; }
                    if (cm.hidden === true) { result += "display:none;"; }
                    if (rowInd === 0) {
                        result += "width: " + grid.headers[pos].width + "px;";
                    } else if (cm.cellattr && $.isFunction(cm.cellattr)) {
                        celp = cm.cellattr.call(ts, rowId, tv, rawObject, cm, rdata);
                        if (celp && typeof celp === "string") {
                            celp = celp.replace(/style/i, 'style').replace(/title/i, 'title');
                            if (celp.indexOf('title') > -1) { cm.title = false; }
                            if (celp.indexOf('class') > -1) { clas = undefined; }
                            acp = celp.replace('-style', '-sti').split(/style/);
                            if (acp.length === 2) {
                                acp[1] = $.trim(acp[1].replace('-sti', '-style').replace("=", ""));
                                if (acp[1].indexOf("'") === 0 || acp[1].indexOf('"') === 0) {
                                    acp[1] = acp[1].substring(1);
                                }
                                result += acp[1].replace(/'/gi, '"');
                            } else {
                                result += "\"";
                            }
                        }
                    }
                    if (!acp.length) { acp[0] = ""; result += "\""; }
                    result += (clas !== undefined ? (" class=\"" + clas + "\"") : "") + ((cm.title && tv) ? (" title=\"" + $.jgrid.stripHtml(tv) + "\"") : "");
                    result += " aria-describedby=\"" + ts.p.id + "_" + nm + "\"";
                    result += " data-vpgrid-column-name=\"" + nm + "\"";
                    return result + acp[0];
                }; // end formatCol

                this.each(function() {
                    var t = this, datalen = rdata.length;
                    ni = t.p.rownumbers===true ? 1 :0;
                    gi = t.p.multiselect ===true ? 1 :0;
                    si = t.p.subGrid===true ? 1 :0;
                    
                    cn = t.p.altclass;
                    var k = 0, cna ="", lcdata = {},
                    air = $.isFunction(t.p.afterInsertRow) ? true : false;
                
                    vpGrid.executeAsyncLoopOnArray(rdata,
                        function (k, data) {
                            try {
                                row = [];
                                var rowIndex = startIndex + k;
                                var rowid = t.p.idPrefix + rowIndex;
                                cna = t.p.altRows === true ? (t.rows.length - 1) % 2 === 0 ? cn : "" : "";
                                id = rowid;
  
                                if (ni) {
                                    prp = t.formatCol(0, 1, '', null, rowid, true);
                                    row[row.length] = "<td role=\"gridcell\" class=\"ui-state-default jqgrid-rownum\" " + prp + ">0</td>";
                                }
                                if (gi) {
                                    //hdo : add disabled attribute to the checkbox
                                    //v = "<input role=\"checkbox\" type=\"checkbox\""+" id=\"jqg_"+t.p.id+"_"+rowid+"\" class=\"cbox\"/>";
                                    v = "<input disabled=\"disabled\" role=\"checkbox\" type=\"checkbox\"" + " id=\"jqg_" + t.p.id + "_" + rowid + "\" class=\"cbox\"/>";

                                    prp = t.formatCol(ni, 1, '', null, rowid, true);

                                    //hdo : inject  data-vpgrid-column-name attribute
                                    var prp2 = ' data-vpgrid-column-name="cb"';

                                    //row[row.length] = "<td role=\"gridcell\" " + prp + ">" + v + "</td>";
                                    row[row.length] = "<td role=\"gridcell\" " + prp + prp2 + ">" + v + "</td>";
                                }
                                if (si) {
                                    row[row.length] = $(t).jqGrid("addSubGridCell", gi + ni, 1);
                                }
                                for (i = gi + si + ni; i < t.p.colModel.length; i++) {
                                    cm = t.p.colModel[i];
                                    nm = cm.name;
                                    lcdata[nm] = data[nm];
                                    v = t.formatter(rowid, $.jgrid.getAccessor(data, nm), i, data);
                                    prp = t.formatCol(i, 1, v, data, rowid, lcdata);
                                    //hdo : inject  data-vpgrid-column-name attribute
                                    var prp2 = ' data-vpgrid-column-name="' + nm + '"';

                                    //row[row.length] = "<td role=\"gridcell\" " + prp + ">" + v + "</td>";
                                    row[row.length] = "<td role=\"gridcell\" " + prp + prp2 + ">" + v + "</td>";

                                }
                                row.unshift(t.constructTr(rowid, false, cna, lcdata, data, false));
                                row[row.length] = "</tr>";
                                if (t.rows.length === 0) {
                                    //hdo
                                    //$("table:first", t.grid.bDiv).append(row.join(''));
                                } else {
                                    switch (pos) {
                                        case 'last':
                                            //hdo
                                            //$(t.rows[t.rows.length - 1]).after(row.join(''));
                                            sind = t.rows.length - 1;
                                            break;
                                        case 'first':
                                            //hdo
                                            //$(t.rows[0]).after(row.join(''));
                                            sind = 1;
                                            break;
                                        case 'after':
                                            sind = $(t).jqGrid('getGridRowById', src);
                                            if (sind) {
                                                //hdo
                                                //if ($(t.rows[sind.rowIndex + 1]).hasClass("ui-subgrid")) { $(t.rows[sind.rowIndex + 1]).after(row); }
                                                //else { $(sind).after(row.join('')); }
                                                sind = sind.rowIndex + 1;
                                            }
                                            break;
                                        case 'before':
                                            sind = $(t).jqGrid('getGridRowById', src);
                                            if (sind) {
                                                //hdo
                                                //$(sind).before(row.join(''));
                                                sind = sind.rowIndex - 1;
                                            }
                                            break;
                                    }
                                }
                                if (t.p.subGrid === true) {
                                    $(t).jqGrid("addSubGrid", gi + ni, sind);
                                }
                                t.p.records++;
                                t.p.reccount++;
                                //$(t).triggerHandler("jqGridAfterInsertRow", [rowid, data, data]);
                                //if (air) { t.p.afterInsertRow.call(t, rowid, data, data); }
                            
                                if (t.p.datatype === 'local') {
                                    lcdata[t.p.localReader.id] = id;
                                    t.p._index[id] = t.p.data.length;
                                    t.p.data.push(lcdata);
                                    lcdata = {};
                                }
                            
                                if (onProgress) {
                                    onProgress.call(t, k);
                                }
                                    
                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        }, // end callback that process item k/data
                        t, // context
                        function () { // onEnd callback
                            try {
                                //if (t.p.altRows === true && !aradd) {
                                //    if (pos === "last") {
                                //        if ((t.rows.length - 1) % 2 === 1) { $(t.rows[t.rows.length - 1]).addClass(cn); }
                                //    } else {
                                //        $(t.rows).each(function (i) {
                                //            if (i % 2 === 1) { $(this).addClass(cn); }
                                //            else { $(this).removeClass(cn); }
                                //        });
                                //    }
                                //}
                                //t.updatepager(true, true);
                                if (onEnd) {
                                    onEnd.call(t);
                                }
                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        },
                        cancel,onCanceled
                        );

                    success = true;
                });
            }
            return success;
        },




        
        //hdo : modified to work with multiple summary rows
        showHideCol : function(colname,show) {
        return this.each(function() {
            var $t = this, fndh=false, brd=$.jgrid.cell_width ? 0: $t.p.cellLayout, cw;
            if (!$t.grid ) {return;}
            if( typeof colname === 'string') {colname=[colname];}
            show = show !== "none" ? "" : "none";
            var sw = show === "" ? true :false,
			gh = $t.p.groupHeader && (typeof $t.p.groupHeader === 'object' || $.isFunction($t.p.groupHeader) );
            if(gh) { $($t).jqGrid('destroyGroupHeader', false); }
            $(this.p.colModel).each(function(i) {
                if ($.inArray(this.name,colname) !== -1 && this.hidden === sw) {
                    if($t.p.frozenColumns === true && this.frozen === true) {
                        return true;
                    }
                    $("tr[role=rowheader]",$t.grid.hDiv).each(function(){
                        $(this.cells[i]).css("display", show);
                    });
                    $($t.rows).each(function(){
                        if (!$(this).hasClass("jqgroup")) {
                            $(this.cells[i]).css("display", show);
                        }
                    });
                    if ($t.p.footerrow) {
                        //hdo : modified to work with multiple summary rows
                        //$("tr.footrow td:eq(" + i + ")", $t.grid.sDiv).css("display", show);
                        var summaryRowscontainer = $t.grid.sDiv;
                        $(summaryRowscontainer).find("tr.footrow").find("td:eq(" + i + ")").css("display", show);
                        
                    }
                    cw =  parseInt(this.width,10);
                    if(show === "none") {
                        $t.p.tblwidth -= cw+brd;
                    } else {
                        $t.p.tblwidth += cw+brd;
                    }
                    this.hidden = !sw;
                    fndh=true;
                    $($t).triggerHandler("jqGridShowHideCol", [sw,this.name,i]);
                }
            });
            if(fndh===true) {
                if($t.p.shrinkToFit === true && !isNaN($t.p.height)) { $t.p.tblwidth += parseInt($t.p.scrollOffset,10);}
                $($t).jqGrid("setGridWidth",$t.p.shrinkToFit === true ? $t.p.tblwidth : $t.p.width );
            }
            if( gh )  {
                $($t).jqGrid('setGroupHeaders',$t.p.groupHeader);
            }
        });
        },




        //hdo : modified to tag the sortable on the right row when columns group header is activated
        sortableColumns : function (tblrow)
        {
            return this.each(function (){
                var ts = this, tid= $.jgrid.jqID( ts.p.id );
                function start() {ts.p.disableClick = true;}
                var sortable_opts = {
                    "tolerance" : "pointer",
                    "axis" : "x",
                    "scrollSensitivity": "1",
                    "items": '>th:not(:has(#jqgh_'+tid+'_cb'+',#jqgh_'+tid+'_rn'+',#jqgh_'+tid+'_subgrid),:hidden)',
                    "placeholder": {
                        element: function(item) {
                            var el = $(document.createElement(item[0].nodeName))
						    .addClass(item[0].className+" ui-sortable-placeholder ui-state-highlight")
						    .removeClass("ui-sortable-helper")[0];
                            return el;
                        },
                        update: function(self, p) {
                            p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10));
                            p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10));
                        }
                    },
                    "update": function(event, ui) {
                        var p = $(ui.item).parent(),
					    th = $(">th", p),
					    colModel = ts.p.colModel,
					    cmMap = {}, tid= ts.p.id+"_";
                        $.each(colModel, function(i) { cmMap[this.name]=i; });
                        var permutation = [];
                        th.each(function() {
                            var id = $(">div", this).get(0).id.replace(/^jqgh_/, "").replace(tid,"");
                            if (cmMap.hasOwnProperty(id)) {
                                permutation.push(cmMap[id]);
                            }
                        });
	
                        $(ts).jqGrid("remapColumns",permutation, true, true);
                        if ($.isFunction(ts.p.sortable.update)) {
                            ts.p.sortable.update(permutation);
                        }
                        setTimeout(function(){ts.p.disableClick=false;}, 50);
                    }
                };
                if (ts.p.sortable.options) {
                    $.extend(sortable_opts, ts.p.sortable.options);
                } else if ($.isFunction(ts.p.sortable)) {
                    ts.p.sortable = { "update" : ts.p.sortable };
                }
                if (sortable_opts.start) {
                    var s = sortable_opts.start;
                    sortable_opts.start = function(e,ui) {
                        start();
                        s.call(this,e,ui);
                    };
                } else {
                    sortable_opts.start = start;
                }
                if (ts.p.sortable.exclude) {
                    sortable_opts.items += ":not("+ts.p.sortable.exclude+")";
                }



                //hdo : tblrow is not the right row when col groups are activated
                
                //var headerRowId = 'colHeader_' + ts.p.id;
                //tblrow.attr('id', headerRowId);
                //tblrow = $('tr#' + headerRowId);

                setTimeout(function () {
                    try {
                        var tblrow = $('div#gview_' + ts.p.id).find('table.ui-jqgrid-htable').find("tr.ui-jqgrid-labels").last();
                        tblrow.sortable(sortable_opts).data("sortable").floating = true;
                    } catch (e) {
                    }
                    
                }, 3000);


                
            });
        },

        //hdo : modified to accelerate the search : twice faster
        getGridRowById_v0: function (rowid) {
            var row;
            this.each(function () {
                try {
                    //row = this.rows.namedItem( rowid );
                    var i1 = Math.floor(this.rows.length / 3);
                    var rowidAsString = rowid.toString();
                    for (var i = 1; i < i1; i++) {
                        if (rowidAsString === this.rows[i].id) {
                            row = this.rows[i];
                            return row;
                        }
                    }
                   
                    var i2 = Math.floor(2 * this.rows.length / 3);
                    for (var i = i1; i < i2; i++) {
                        if (rowidAsString === this.rows[i].id) {
                            row = this.rows[i];
                            return row;
                        }
                    }
                    
                    var i3 = this.rows.length;
                    for (var i = i2; i < i3; i++) {
                        if (rowidAsString === this.rows[i].id) {
                            row = this.rows[i];
                            return row;
                        }
                    }
                    
                } catch (e) {
                    row = $(this.grid.bDiv).find("#" + $.jgrid.jqID(rowid));
                    return row;
                }
            });
            return row;
        },




        //hdo : modified to accelerate the search for a specific row : 3times faster
        // the idea is that probability is higher to find the searched row near the previous found row
        // the grid rows are partitionned into N areas (N=10) 
        // and search is first focus on the the area where the previous search found the row. 
        // If not found search is done in adjacent areas
        getGridRowById: function (rowid) {
            var row;
            this.each(function () {
                try {
                    //get latest search partition Identifier
                    var lastPartition = this.lastSearchPartitionId || 1;
                    var rowidAsString = rowid.toString();
                    row = $.jgrid.searchOnPartitions.call(this, rowidAsString, lastPartition);
                    //console.log(lastPartition);
                    return row;

                } catch (e) {
                    row = $(this.grid.bDiv).find("#" + $.jgrid.jqID(rowid));
                    return row;
                }
            });
            return row;
    }



    });

    $.extend($.jgrid, {
        //hdo : modified to handle the case val  is null
        //hdo : modified to handle the case a white space is translated to a strange char by IE 7/8/9
        isEmpty: function (val) {
            if (val === null) {
                return true;
            }

            if (val === "") {
                return true;
            }

            if (val.match === undefined) {
                return false;
            }

            if (val.match(/^\s+$/) ) {
                return true;
            }

            if (typeof val.isNullOrEmptyOrWhitespace === "function" && val.isNullOrEmptyOrWhitespace()) {
                return true;
            }

            return false;
        },
        
        //hdo : modified to pass a datarow object when validating out of the grid
        checkValues: function (val, valref, customobject, nam, dataRow) {
            var edtrul, i, nm, dft, len, g = this, cm = g.p.colModel;
            if (customobject === undefined) {
                if (typeof valref === 'string') {
                    for (i = 0, len = cm.length; i < len; i++) {
                        if (cm[i].name === valref) {
                            edtrul = cm[i].editrules;
                            valref = i;
                            if (cm[i].formoptions != null) { nm = cm[i].formoptions.label; }
                            break;
                        }
                    }
                } else if (valref >= 0) {
                    edtrul = cm[valref].editrules;
                }
            } else {
                edtrul = customobject;
                nm = nam === undefined ? "_" : nam;
            }
            if (edtrul) {
                if (!nm) { nm = g.p.colNames != null ? g.p.colNames[valref] : cm[valref].label; }

                //hdo : nm might be empty because the column is hidden in the grid but not in the ui-dialog form
                if (nm !== "") { nm = nm + ": "; }

                if (edtrul.required === true) {
                    //hdo
                    //if ($.jgrid.isEmpty(val)) { return [false, nm + ": " + $.jgrid.edit.msg.required, ""]; }
                    if ($.jgrid.isEmpty(val)) { return [false, nm + $.jgrid.edit.msg.required, ""]; }
                }
                // force required
                var rqfield = edtrul.required === false ? false : true;
                if (edtrul.number === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        //hdo
                        //if (isNaN(val)) { return [false, nm + ": " + $.jgrid.edit.msg.number, ""]; }
                        if (isNaN(val)) { return [false, nm + $.jgrid.edit.msg.number, ""]; }
                    }
                }
                if (edtrul.minValue !== undefined && !isNaN(edtrul.minValue)) {
                    //if (parseFloat(val) < parseFloat(edtrul.minValue) ) { return [false,nm+": "+$.jgrid.edit.msg.minValue+" "+edtrul.minValue,""];}
                    if (parseFloat(val) < parseFloat(edtrul.minValue)) {
                        //hdo
                        //var errorMessage = nm + ": " + $.jgrid.edit.msg.minValue + " " + edtrul.minValue;
                        var errorMessage = nm  + $.jgrid.edit.msg.minValue + " " + edtrul.minValue;
                        return [false, errorMessage, ""];
                    }


                }
                if (edtrul.maxValue !== undefined && !isNaN(edtrul.maxValue)) {
                    //if (parseFloat(val) > parseFloat(edtrul.maxValue)) { return [false, nm + ": " + $.jgrid.edit.msg.maxValue + " " + edtrul.maxValue, ""]; }
                    if (parseFloat(val) > parseFloat(edtrul.maxValue)) { return [false, nm  + $.jgrid.edit.msg.maxValue + " " + edtrul.maxValue, ""]; }
                }
                var filter;
                if (edtrul.email === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        // taken from $ Validate plugin
                        filter = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i;
                        if (!filter.test(val)) { return [false, nm + ": " + $.jgrid.edit.msg.email, ""]; }
                    }
                }
                if (edtrul.integer === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        //if (isNaN(val)) { return [false, nm + ": " + $.jgrid.edit.msg.integer, ""]; }
                        if (isNaN(val)) { return [false, nm + $.jgrid.edit.msg.integer, ""]; }
                        //if ((val % 1 !== 0) || (val.indexOf('.') !== -1)) { return [false, nm + ": " + $.jgrid.edit.msg.integer, ""]; }
                        if ((val % 1 !== 0) || (val.indexOf('.') !== -1)) { return [false, nm + $.jgrid.edit.msg.integer, ""]; }
                    }
                }
                if (edtrul.date === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        if (cm[valref].formatoptions && cm[valref].formatoptions.newformat) {
                            dft = cm[valref].formatoptions.newformat;
                            if ($.jgrid.formatter.date.masks.hasOwnProperty(dft)) {
                                dft = $.jgrid.formatter.date.masks[dft];
                            }
                        } else {
                            dft = cm[valref].datefmt || "Y-m-d";
                        }
                        //if (!$.jgrid.checkDate(dft, val)) { return [false, nm + ": " + $.jgrid.edit.msg.date + " - " + dft, ""]; }
                        if (!$.jgrid.checkDate(dft, val)) { return [false, nm + $.jgrid.edit.msg.date + " - " + dft, ""]; }
                    }
                }
                if (edtrul.time === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        //if (!$.jgrid.checkTime(val)) { return [false, nm + ": " + $.jgrid.edit.msg.date + " - hh:mm (am/pm)", ""]; }
                        if (!$.jgrid.checkTime(val)) { return [false, nm  + $.jgrid.edit.msg.date + " - hh:mm (am/pm)", ""]; }
                    }
                }
                if (edtrul.url === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        filter = /^(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
                        if (!filter.test(val)) { return [false, nm + ": " + $.jgrid.edit.msg.url, ""]; }
                    }
                }
                if (edtrul.custom === true) {
                    //hdo : always call the the custom validation function
                    //      in order to be able to implement a conditional required content based on custom business rules
                    //if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        if ($.isFunction(edtrul.custom_func)) {
                            var ret = edtrul.custom_func.call(g, val, nm, valref,dataRow);
                            return $.isArray(ret) ? ret : [false, $.jgrid.edit.msg.customarray, ""];
                        }
                        return [false, $.jgrid.edit.msg.customfcheck, ""];
                    //} // end if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                }
            }
            return [true, "", ""];
        },

        searchOnPartitionWithIndex: function (rowid, partitionIndex, partitionNumbers) {
            var row;
            try {
                // Index of a partition starts at 1
                if (partitionIndex <= 0) {
                    partitionIndex = 1;
                }

                var iFirst = Math.floor((partitionIndex - 1) * this.rows.length / partitionNumbers);
                iFirst = Math.max(1, iFirst);

                var iLast = Math.floor(partitionIndex * this.rows.length / partitionNumbers)
                iLast = Math.min(iLast, this.rows.length);

                for (var i = iFirst; i < iLast; i++) {
                    if (rowid === this.rows[i].id) {
                        row = this.rows[i];
                        return row;
                    }
                }

            } catch (e) {
                vpGrid.logException(e);
                row = $(this.grid.bDiv).find("#" + $.jgrid.jqID(rowid));
            }
            return row;
        },

        searchOnPartitions: function (rowid, lastPartition) {
            var row;
            try {

                var startPartition = lastPartition;
                var maxPartitions = 10;
                
                for (var i = lastPartition; i <= maxPartitions; i++) {
                    row = $.jgrid.searchOnPartitionWithIndex.call(this, rowid, i, maxPartitions);
                    if (row) {
                        this.lastSearchPartitionId = i;
                        return row;
                    }
                }

                for (var i = 1; i < startPartition; i++) {
                    row = $.jgrid.searchOnPartitionWithIndex.call(this, rowid, i, maxPartitions);
                    if (row) {
                        this.lastSearchPartitionId = i;
                        return row;
                    }
                }

                //not found

            } catch (e) {
                vpGrid.logException(e);
                row = $(this.grid.bDiv).find("#" + $.jgrid.jqID(rowid));
            }
            return row;

        }


    });
})(jQuery);
/* End jqGrid extensions */